diff --git a/.clang-format b/.clang-format index 3c68a1a7a..8c5619f35 100644 --- a/.clang-format +++ b/.clang-format @@ -54,6 +54,7 @@ IncludeCategories: IndentCaseLabels: false IndentWidth: 4 IndentWrappedFunctionNames: false +InsertNewlineAtEOF: true KeepEmptyLinesAtTheStartOfBlocks: true MacroBlockBegin: '' MacroBlockEnd: '' @@ -81,7 +82,7 @@ SpacesInContainerLiterals: true SpacesInCStyleCastParentheses: false SpacesInParentheses: false SpacesInSquareBrackets: false -Standard: Cpp11 +Standard: c++17 TabWidth: 4 UseTab: Never ... diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index 6de956328..062c0973a 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -15,6 +15,7 @@ These are just guidelines, not rules. Use your best judgment, and feel free to p * [Bug reports](#bug-reports) * [Discuss with the team](#discuss-with-the-team) * [Your first code contribution](#your-first-code-contribution) + * [Using AI](#using-ai) * [Pull requests](#pull-requests) * [Translations](#translations) @@ -38,7 +39,7 @@ We will accept contributions of good code that we can use from anyone. - “contributions”: This means just about anything you wish to contribute to the project, as long as it is good code we can use. The easier you make it for us to accept your contribution, the happier we are, but if it’s good enough, we will do a reasonable amount of work to use it. - “of good code”: This means that we will accept contributions that work well and efficiently, that fit in with the goals of the project, that match the project’s coding style, and that do not impose an undue maintenance workload on us going forward. This does not mean just program code, either, but documentation and artistic works as appropriate to the project. - “that we can use”: This means that your contribution must be given freely and irrevocably, that you must have the right to contribute it for our unrestricted use, and that your contribution is made under a license that is compatible with the license the project has chosen and that permits us to include, distribute, and modify your work without restriction. - - “from anyone”: This means exactly that. We don’t care about anything but your code. We don’t care about your race, religion, national origin, biological gender, perceived gender, sexual orientation, lifestyle, political viewpoint, or anything extraneous like that. We will neither reject your contribution nor grant it preferential treatment on any basis except the code itself. We do, however, reserve the right to tell you to go away if you behave too obnoxiously toward us. + - “from anyone”: This means exactly that. We don’t care about anything but your code. We don’t care about your race, religion, national origin, biological gender, perceived gender, sexual orientation, lifestyle, political viewpoint, or anything extraneous like that. We will neither reject your contribution nor grant it preferential treatment on any basis except the code itself. We do, however, reserve the right to limit your access to our community if you violate our [Code of Conduct](../CODE-OF-CONDUCT.md). #### If Your Contribution Is Rejected @@ -74,6 +75,10 @@ Unsure where to begin contributing to KeePassXC? You can start by looking throug Both issue lists are sorted by total number of comments. While not perfect, looking at the number of comments on an issue can give a general idea of how much an impact a given change will have. +### Using AI + +Generative AI is fast becoming a first-party feature in most development environments, including GitHub itself. If you use Generative AI to write the vast majority of your submission (e.g., agent-based or vibe coding) then you **must document your use of AI** in your pull request. Please include the service you used and/or model that generated the code. All code submissions go through a rigorous review process regardless of the development workflow used. + ### Pull requests Along with our desire to hear your feedback and suggestions, we're also interested in accepting direct assistance in the form of code. diff --git a/.github/ISSUE_TEMPLATE/bug-report.md b/.github/ISSUE_TEMPLATE/bug-report.md deleted file mode 100644 index a4a3ae2cd..000000000 --- a/.github/ISSUE_TEMPLATE/bug-report.md +++ /dev/null @@ -1,39 +0,0 @@ ---- -name: Bug Report -about: provide information about a problem -title: -labels: bug -assignees: '' - ---- -## Overview -[TIP]: # ( DO NOT include screenshots of your actual database! ) -[NOTE]: # ( Give a BRIEF summary about your problem ) - - -## Steps to Reproduce -[NOTE]: # ( Provide a simple set of steps to reproduce this bug. ) -1. -2. -3. - -## Expected Behavior -[NOTE]: # ( Tell us what you expected to happen ) - - -## Actual Behavior -[NOTE]: # ( Tell us what actually happens ) - - -## Context -[NOTE]: # ( Give us any additional information you may have. ) - - -[NOTE]: # ( Paste debug info from Help → About here ) -KeePassXC - VERSION -Revision: REVISION - -[NOTE]: # ( Pick choices based on your environment ) -Operating System: Windows/Linux/macOS -Desktop Env: Gnome/KDE/XFCE/Mate/Cinnamon -Windowing System: X11/Wayland \ No newline at end of file diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml new file mode 100644 index 000000000..557f4a4d9 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -0,0 +1,83 @@ +name: Bug Report +description: Provide information about a problem you are experiencing. +type: Bug + +body: + - type: checkboxes + attributes: + label: Have you searched for an existing issue? + description: | + Use the issue search box to see if one already exists for the bug you encountered. + Also take a moment to review our pinned issues. + options: + - label: Yes, I tried searching and reviewed the pinned issues + required: true + + - type: textarea + id: summary + attributes: + label: Brief Summary + description: | + Provide an overview of the problem, include any information that may help us triage this issue. + Provide screenshots if possible, but do NOT show sensitive data (use View -> Allow Screen Capture). + validations: + required: true + + - type: textarea + id: steps + attributes: + label: Steps to Reproduce + description: Provide a simple set of steps to reproduce this bug. + placeholder: | + 1. + 2. + 3. + validations: + required: true + + - type: textarea + id: expected_vs_actual + attributes: + label: Expected Versus Actual Behavior + description: Tell us what you expected to happen and what actually happened. + + - type: textarea + id: debug_info + attributes: + label: KeePassXC Debug Information + placeholder: "Paste the output of: Help -> About -> Debug Info" + render: Text + + - type: dropdown + id: os + attributes: + label: Operating System + description: Select your operating system. + options: + - Windows + - Linux + - macOS + - Other (BSD, Haiku, etc) + + - type: dropdown + id: desktop_env + attributes: + label: Linux Desktop Environment + description: If on Linux, please select your desktop environment. + options: + - Gnome + - KDE + - XFCE + - Mate / Cinnamon + - Sway + - i3 + - Other + + - type: dropdown + id: window_system + attributes: + label: Linux Windowing System + description: If on Linux, please select your windowing system. + options: + - X11 + - Wayland diff --git a/.github/ISSUE_TEMPLATE/feature-request.md b/.github/ISSUE_TEMPLATE/feature-request.md deleted file mode 100644 index d213b4fa3..000000000 --- a/.github/ISSUE_TEMPLATE/feature-request.md +++ /dev/null @@ -1,19 +0,0 @@ ---- -name: Feature Request -about: tell us about a new feature you want -title: -labels: new feature -assignees: '' - ---- -## Summary -[TIP]: # ( DO NOT include screenshots of your actual database! ) -[NOTE]: # ( Provide a brief overview of what the new feature is all about ) - - -## Examples -[NOTE]: # ( Show us a picture or mock-up of your proposal ) - - -## Context -[NOTE]: # ( Why does this feature matter to you? What unique circumstances do you have? ) diff --git a/.github/ISSUE_TEMPLATE/feature_request.yml b/.github/ISSUE_TEMPLATE/feature_request.yml new file mode 100644 index 000000000..90f543440 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.yml @@ -0,0 +1,34 @@ +name: Feature Request +description: Tell us about a new feature you want. +type: Feature + +body: + - type: checkboxes + attributes: + label: Have you searched for an existing feature request? + description: Use the issue search box to see if one already exists for the feature you want. + options: + - label: Yes, I tried searching + required: true + + - type: textarea + id: summary + attributes: + label: Brief Summary + description: | + Provide an overview of the feature you are interested in adding. + Provide screenshots if possible, but do NOT show sensitive data (use View -> Allow Screen Capture). + validations: + required: true + + - type: textarea + id: example + attributes: + label: Example + description: Provide an example of how this feature would be used. + + - type: textarea + id: context + attributes: + label: Context + description: Why does this feature matter to you? What unique circumstances do you have? diff --git a/.github/ISSUE_TEMPLATE/prerelease_bug_report.yml b/.github/ISSUE_TEMPLATE/prerelease_bug_report.yml new file mode 100644 index 000000000..10c5d855c --- /dev/null +++ b/.github/ISSUE_TEMPLATE/prerelease_bug_report.yml @@ -0,0 +1,85 @@ +name: Pre-Release Bug Report +description: Report an issue with pre-release code (e.g. snapshot builds). +type: Bug +labels: PRE-RELEASE BUG +assignees: droidmonkey + +body: + - type: checkboxes + attributes: + label: Have you searched for an existing issue? + description: | + Use the issue search box to see if one already exists for the bug you encountered. + Also take a moment to review our pinned issues. + options: + - label: Yes, I tried searching and reviewed the pinned issues + required: true + + - type: textarea + id: summary + attributes: + label: Brief Summary + description: | + Provide an overview of the problem, include any information that may help us triage this issue. + Provide screenshots if possible, but do NOT show sensitive data (use View -> Allow Screen Capture). + validations: + required: true + + - type: textarea + id: steps + attributes: + label: Steps to Reproduce + description: Provide a simple set of steps to reproduce this bug. + placeholder: | + 1. + 2. + 3. + validations: + required: true + + - type: textarea + id: expected_vs_actual + attributes: + label: Expected Versus Actual Behavior + description: Tell us what you expected to happen and what actually happened. + + - type: textarea + id: debug_info + attributes: + label: KeePassXC Debug Information + placeholder: "Paste the output of: Help -> About -> Debug Info" + render: Text + + - type: dropdown + id: os + attributes: + label: Operating System + description: Select your operating system. + options: + - Windows + - Linux + - macOS + - Other (BSD, Haiku, etc) + + - type: dropdown + id: desktop_env + attributes: + label: Linux Desktop Environment + description: If on Linux, please select your desktop environment. + options: + - Gnome + - KDE + - XFCE + - Mate / Cinnamon + - Sway + - i3 + - Other + + - type: dropdown + id: window_system + attributes: + label: Linux Windowing System + description: If on Linux, please select your windowing system. + options: + - X11 + - Wayland diff --git a/.github/ISSUE_TEMPLATE/release-preview-bug-report.md b/.github/ISSUE_TEMPLATE/release-preview-bug-report.md deleted file mode 100644 index b2fbf65ff..000000000 --- a/.github/ISSUE_TEMPLATE/release-preview-bug-report.md +++ /dev/null @@ -1,39 +0,0 @@ ---- -name: Release Preview Bug report -about: report a bug with a release preview (e.g., 2.6.0-beta1) -title: -labels: PRE-RELEASE BUG -assignees: droidmonkey - ---- -## Overview -[TIP]: # ( DO NOT include screenshots of your actual database! ) -[NOTE]: # ( Give a BRIEF summary about your problem ) - - -## Steps to Reproduce -[NOTE]: # ( Provide a simple set of steps to reproduce this bug. ) -1. -2. -3. - -## Expected Behavior -[NOTE]: # ( Tell us what you expected to happen ) - - -## Actual Behavior -[NOTE]: # ( Tell us what actually happens ) - - -## Context -[NOTE]: # ( Give us any additional information you may have. ) - - -[NOTE]: # ( Paste debug info from Help → About here ) -KeePassXC - VERSION -Revision: REVISION - -[NOTE]: # ( Pick choices based on your environment ) -Operating System: Windows/Linux/macOS -Desktop Env: Gnome/KDE/XFCE/Mate/Cinnamon -Windowing System: X11/Wayland \ No newline at end of file diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index e75bbcd60..5e039d00b 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -1,15 +1,16 @@ -[NOTE]: # ( Describe your changes in detail, why is this change required? ) -[NOTE]: # ( Explain large or complex code modifications. ) -[NOTE]: # ( If it fixes an open issue, please add "Fixes #XXX" ) +[NOTE]: # ( Describe your changes in detail. Explain large or complex code modifications. ) +[NOTE]: # ( If it fixes an open issue, please add "Fixes #XXX". ) +[NOTE]: # ( If you used Generative AI to write the majority of your code, you must state this. ) ## Screenshots -[TIP]: # ( Do not include screenshots of your actual database! ) +[NOTE]: # ( Do not include screenshots of your actual database! ) +[TIP]: # ( Use View -> Allow Screen Capture ) ## Testing strategy [NOTE]: # ( Please describe in detail how you tested your changes. ) -[TIP]: # ( We expect new code to be covered by unit tests and documented with doc blocks! ) +[TIP]: # ( We expect new code to be covered by unit tests and include helpful comments. ) ## Type of change diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md new file mode 100644 index 000000000..0eb7156bf --- /dev/null +++ b/.github/copilot-instructions.md @@ -0,0 +1,38 @@ +This is a C++ based repository that uses Qt5 as a primary support and GUI library. This repository is for a password manager application that stores passwords +and other highly sensitive information. The data format that passwords are stored is called KDBX which is a mixed binary and XML format that is fully encrypted +at rest. This format is unpacked into a series of data structures: Database, Groups, and Entries. Please follow these guidelines when contributing: + +## Code Standards + +### Required Before Each Commit +- Run `cmake --build . --target format` before committing any changes to ensure proper code formatting +- This will run clang-format to ensure all code conforms to the style guide +- From the checkout directory, also run `./release-tool i18n lupdate` to update translation files + +### Development Flow +- Setup Build Folder: `mkdir build; cd build` +- Configure: `cmake -G Ninja -DWITH_XC_ALL=ON -DWITH_GUI_TESTS=ON ..` +- Build: `cmake --build . -- -j $(nproc)` +- Test: `ctest` + +## Repository Structure +- `docs/topics`: Documentation written in asciidoctor syntax +- `src/`: Main source code files are under this subdirectory +- `src/autotype`: Code that emulates a virtual keyboard to type into interfaces +- `src/browser`: Interface with the KeePassXC Browser Extension using a JSON-based protocol +- `src/cli`: Command Line Interface code +- `src/core`: Contains files that define the data model and other shared code structures +- `src/format`: Code for import/export and reading/writing of KDBX databases +- `src/fdosecrets`: freedesktop.org Secret Service interface code +- `src/quickunlock`: Quick unlock interfaces for various platforms +- `src/sshagent`: SSH Agent interface code to load private keys from the database into ssh-agent +- `tests/`: Test source code files +- `tests/gui`: GUI test source code files + +## Key Guidelines +1. Follow C++20 and Qt5 best practices and idiomatic patterns +2. Maintain existing code structure and organization +3. Prefer not to edit cryptographic handling code or other sensitive parts of the code base +4. Write unit tests for new functionality using QTest scaffolding +5. Suggest changes to the `docs/topics` folder when appropriate +6. Unless the change is simple, don't actually make edits to .ui files, just suggest the changes needed diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml new file mode 100644 index 000000000..80af12490 --- /dev/null +++ b/.github/workflows/codeql.yml @@ -0,0 +1,70 @@ +name: "CodeQL" + +on: + push: + branches: [ 'develop', 'release/2.7.x' ] + pull_request: + # The branches below must be a subset of the branches above + branches: [ 'develop' ] + schedule: + - cron: '5 16 * * 3' + +jobs: + analyze: + name: Analyze + runs-on: ${{ (matrix.language == 'swift' && 'macos-latest') || 'ubuntu-latest' }} + timeout-minutes: ${{ (matrix.language == 'swift' && 120) || 360 }} + permissions: + actions: read + contents: read + security-events: write + + strategy: + fail-fast: false + matrix: + language: [ 'cpp' ] + # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ] + # Use only 'java' to analyze code written in Java, Kotlin or both + # Use only 'javascript' to analyze code written in JavaScript, TypeScript or both + # Learn more about CodeQL language support at https://aka.ms/codeql-docs/language-support + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - if: matrix.language == 'cpp' + name: Install dependencies + run: | + sudo apt update + sudo apt install build-essential cmake g++ + sudo apt install qtbase5-dev qtbase5-private-dev qttools5-dev qttools5-dev-tools libqt5svg5-dev libargon2-dev libkeyutils-dev libminizip-dev libbotan-2-dev libqrencode-dev zlib1g-dev asciidoctor libreadline-dev libpcsclite-dev libusb-1.0-0-dev libxi-dev libxtst-dev libqt5x11extras5-dev + + # Initializes the CodeQL tools for scanning. + - name: Initialize CodeQL + uses: github/codeql-action/init@v3 + with: + languages: ${{ matrix.language }} + # If you wish to specify custom queries, you can do so here or in a config file. + # By default, queries listed here will override any specified in a config file. + # Prefix the list here with "+" to use these queries and those in the config file. + + # For more details on CodeQL's query packs, refer to: https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs + queries: security-and-quality + + - if: matrix.language == 'cpp' + name: Build C++ + run: | + mkdir build && cd build + cmake -DWITH_XC_ALL=ON -DWITH_TESTS=OFF .. + make -j $(nproc) + + # Autobuild attempts to build any compiled languages (C/C++, C#, Go, Java, or Swift). + # If this step fails, then you should remove it and run the build manually (see below) + - if: matrix.language != 'cpp' + name: Autobuild + uses: github/codeql-action/autobuild@v3 + + - name: Perform CodeQL Analysis + uses: github/codeql-action/analyze@v3 + with: + category: "/language:${{matrix.language}}" diff --git a/.github/workflows/copilot-setup-steps.yml b/.github/workflows/copilot-setup-steps.yml new file mode 100644 index 000000000..cfd6b46e7 --- /dev/null +++ b/.github/workflows/copilot-setup-steps.yml @@ -0,0 +1,29 @@ +name: "Copilot Setup Steps" + +# Setup the environment for Copilot agents to run in +on: + workflow_dispatch: + push: + paths: + - .github/workflows/copilot-setup-steps.yml + pull_request: + paths: + - .github/workflows/copilot-setup-steps.yml + +jobs: + copilot-setup-steps: + runs-on: ubuntu-latest + + # Needed to clone the repository + permissions: + contents: read + + # Install dependencies + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Install dependencies + run: | + sudo apt update + sudo apt install --no-install-recommends build-essential cmake g++ ninja-build qtbase5-dev qtbase5-private-dev qttools5-dev qttools5-dev-tools libqt5svg5-dev libargon2-dev libkeyutils-dev libminizip-dev libbotan-2-dev libqrencode-dev zlib1g-dev asciidoctor libreadline-dev libpcsclite-dev libusb-1.0-0-dev libxi-dev libxtst-dev libqt5x11extras5-dev diff --git a/.gitignore b/.gitignore index 766c9018f..d3ee55d43 100644 --- a/.gitignore +++ b/.gitignore @@ -24,6 +24,7 @@ desktop.ini # MSVC Files CMakeSettings.json CMakePresets.json +CMakeUserPresets.json .vs/ out/ diff --git a/.tx/config b/.tx/config index 83910523a..82aefce42 100644 --- a/.tx/config +++ b/.tx/config @@ -1,17 +1,19 @@ [main] -host = https://app.transifex.com +host = https://www.transifex.com [o:keepassxc:p:keepassxc:r:share-translations-keepassxc-en-ts--develop] -file_filter = share/translations/keepassxc_.ts -source_file = share/translations/keepassxc_en.ts -type = QT -minimum_perc = 0 -resource_name = keepassxc_en.ts (develop) +file_filter = share/translations/keepassxc_.ts +source_file = share/translations/keepassxc_en.ts +source_lang = en +type = QT +replace_edited_strings = false +keep_translations = false [o:keepassxc:p:keepassxc:r:share-translations-keepassxc-en-ts--master] -file_filter = share/translations/keepassxc_.ts -source_file = share/translations/keepassxc_en.ts -type = QT -minimum_perc = 0 -resource_name = keepassxc_en.ts (2.7.x stable) +file_filter = share/translations/keepassxc_.ts +source_file = share/translations/keepassxc_en.ts +source_lang = en +type = QT +replace_edited_strings = false +keep_translations = false diff --git a/CHANGELOG.md b/CHANGELOG.md index 0f5ab1f3a..4a7bb20d0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,99 @@ # Changelog +## 2.8.0 (Pending) +* Placeholder for future release notes + +## 2.7.10 (2025-03-02) + +### Changes +* Allow adjusting application font size [#11567] +* Add Proton Pass importer [#11197] +* Support KeePass2 TOTP settings [#11229] +* Add New/Preview Entry Attachments dialog and functionality [#11637, #11699, #11650] +* Add database name, color, and icon options for unlock view [#10819, #11725] +* Show entry background color as column [#6798] +* Use icons for password strength [#9844] +* Add "Group Full Path" column in entry view [#10278] +* Passphrase "MIXED case" Type [#11255] +* Allow deleting extension plugin data from Browser Statistics [#11218] +* Add --minimized option to keepassxc [#11693] +* Implement T-CONV and T-REPLACE-RX entry placeholders [#11453] +* Option to disable opening browser when URL field double-clicked [#11332] +* Overhaul action states and add icons to toolbar [#11047] +* Show character count in password generator dialog [#10940] +* Add ability to expire entries from context menu [#8731] +* Add copy field shortcuts to Auto-Type select dialog [#11518] +* Passkeys: Add support for selecting group on creation [#11260] +* Browser: Refactor Access Control Dialog [#9607] +* Browser: Add support for URL wildcards and exact URL [#9835, #11752] +* Browser: Allow groups to restrict by browser integration key [#9852] +* CLI: Add `-d` dry-run shortcut to merge command [#11192] +* CLI: HTML export [#11590] +* macOS: Add option to disable database lock when switching user [#9707] +* SSH Agent: Implement feature to clear all identities [#10649] + +### Fixes +* Major enhancements to documentation [#11745, #10875] +* Various UI and style fixes [#11535, #11672, #11511, #11445, #11426, #11273, #11455, #11321, #11594, #11539, #11351, #11354, #10748, #11602, #11303, #11291, #10091, #9417] +* Various improvements to tags [#11676, #11652, #11625] +* Reset splitter sizes on database unlock [#11014] +* Remember sort order in Auto-type popup dialog [#9508] +* Fix database password clearing when modifying key file / hardware key [#11001] +* Fix issues with reloading and handling of externally modified db file [#10612] +* Support passkeys with Bitwarden import [#11401] +* Fix various quirks with CSV import [#11787] +* Show Auto-Type select dialog even if window title is empty [#11603] +* Refactor hardware key code to avoid deadlock [#11703, #10872] +* Show a clear error if hardware key is found slots are not configured [#11609] +* Fix signal/slot disconnect when opening import wizard [#11039] +* Fix setting window title as modified [#11542] +* Fix assert hit when viewing entry history [#11413] +* Fix multiple crashes on Linux [#11513] +* Fix backup file path time substitution [#10834] +* Prevent long-running threads from deadlocking the program with only 1 CPU [#11155] +* Hide the menubar when menus lose focus (if toggled off) [#11355, #11605] +* CLI: Restore the original codepage on windows [#11470] +* Passkeys: Various fixes [#10934, #10951] +* Browser: Fix cancel with database unlock dialog [#11435] +* Browser: Resolve references in Access Confirm dialog [#11055] +* SSH Agent: Add timeout to streams to prevent deadlock [#11290] +* macOS: Replace legacy code for screen recording permissions [#11428] +* macOS: Implement Secure Input Mode [#11623] +* macOS: Fix showing ambigious name in settings [#11373] +* macOS: Fix copy-to-clipboard shortcut in entry preview widget [#10966] +* Linux: Prevent multiple lock requests [#11306] +* Snap: Prevent need for snap helper script to configure browser extension [#10924] +* Windows: Detect outdated VC Redist with MSI installer [#11469] +* Windows: Additional exclusion fields for clipboard [#11521] + +## 2.7.9 (2024-06-19) + +### Changes +* Passkeys: Ability to easily remove a passkey from an entry [#10777] +* Snap: Use new desktop portal for native messaging integration [#10906] + +### Fixes +* Improve entry placeholder/reference feature [#10846] +* Improve CSV importing when title field isn't specified [#10843] +* Improve encrypted Bitwarden importing [#10800] +* Improve database settings UX [#10821] +* Improve handling of clipboard actions from entry preview [#10810] +* Improve group/entry view resize behavior and set sensible defaults [#10641] +* Passkeys: Fix incorrect username fill [#10874] +* Passkeys: Return additional data to the extension [#10857] +* Fix password clear timer inconsistency on unlock view [#10708] +* Fix portability check [#10760] +* Fix page overflow on HTML exports [#10735] +* Fix broken builds when using system provided zxcvbn [#10717] +* Fix copy password button when text is selected [#10853] +* Fix tab ordering on application settings pages [#10907] +* SSH Agent: Fix broken decrypt button [#10638] +* Windows: Fix ALT Auto-Type modifier [#10795] +* Windows: Fix wrong DACL memory size allocation [#10712] +* macOS: Fix monospace font sizing [#10739] +* Flatpak: Fix configuration settings off-by-one error [#10688] +* BSD: Fix compiling with libusb implementation [#10736] + ## 2.7.8 (2024-05-05) ### Changes @@ -147,7 +241,7 @@ - Browser: Revert code causing connection problems [#8665] - Browser: Fix socket file symbolic link on Linux [#8656] - Flatpak: Fix launching browser proxy service [#8680] -- SSH Agent: Fix paegent support on Windows [#8619] +- SSH Agent: Fix pageant support on Windows [#8619] ## 2.7.3 (2022-10-23) @@ -1030,7 +1124,7 @@ - Compare window title to entry URLs #556 - Implemented inline error messages #162 - Ignore group expansion and other minor changes when making database "dirty" #464 -- Updated license and copyright information on souce files #632 +- Updated license and copyright information on source files #632 - Added contributors list to about dialog #629 ## 2.1.4 (2017-04-09) diff --git a/CMakeLists.txt b/CMakeLists.txt index 490bf686a..e7183f169 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -120,8 +120,8 @@ if(UNIX AND NOT APPLE AND NOT WITH_XC_X11) endif() set(KEEPASSXC_VERSION_MAJOR "2") -set(KEEPASSXC_VERSION_MINOR "7") -set(KEEPASSXC_VERSION_PATCH "8") +set(KEEPASSXC_VERSION_MINOR "8") +set(KEEPASSXC_VERSION_PATCH "0") set(KEEPASSXC_VERSION "${KEEPASSXC_VERSION_MAJOR}.${KEEPASSXC_VERSION_MINOR}.${KEEPASSXC_VERSION_PATCH}") set(OVERRIDE_VERSION "" CACHE STRING "Override the KeePassXC Version for Snapshot builds") @@ -310,7 +310,7 @@ if(CMAKE_BUILD_TYPE_LOWER STREQUAL "debug") check_add_gcc_compiler_flag("-Wshadow-compatible-local") check_add_gcc_compiler_flag("-Wshadow-local") add_gcc_compiler_flags("-Werror") - # This is needed since compiling aginst Botan3 requires compiling against C++20 + # This is needed since compiling against Botan3 requires compiling against C++20 if(WITH_XC_BOTAN3) add_gcc_compiler_cxxflags("-Wno-error=deprecated-enum-enum-conversion -Wno-error=deprecated") endif() @@ -395,7 +395,7 @@ if (MSVC) if(MSVC_TOOLSET_VERSION LESS 141) message(FATAL_ERROR "Only Microsoft Visual Studio 17 and newer are supported!") endif() - add_compile_options(/permissive- /utf-8) + add_compile_options(/permissive- /utf-8 /MP) if(IS_DEBUG_BUILD) add_compile_options(/Zf) if(MSVC_TOOLSET_VERSION GREATER 141) @@ -467,7 +467,7 @@ if(WITH_COVERAGE) append_coverage_compiler_flags() set(COVERAGE_EXCLUDES - "'^(.+/)?(thirdparty|zxcvbn)/.*'" + "'^(.+/)?thirdparty/.*'" "'^(.+/)?main\\.cpp$$'" "'^(.+/)?cli/keepassxc-cli\\.cpp$$'" "'^(.+/)?proxy/keepassxc-proxy\\.cpp$$'") @@ -512,14 +512,8 @@ else() find_package(Qt5 COMPONENTS ${QT_COMPONENTS} REQUIRED) endif() -if(Qt5Core_VERSION VERSION_LESS "5.2.0") - message(FATAL_ERROR "Qt version 5.2.0 or higher is required") -endif() - -# CBOR for Passkeys requires Qt 5.12 if(Qt5Core_VERSION VERSION_LESS "5.12.0") - message(STATUS "Qt version 5.12.0 or higher is required for Passkeys support") - set(WITH_XC_BROWSER_PASSKEYS OFF) + message(FATAL_ERROR "Qt version 5.12.0 or higher is required") endif() get_filename_component(Qt5_PREFIX ${Qt5_DIR}/../../.. REALPATH) @@ -613,6 +607,12 @@ endif() include_directories(SYSTEM ${ZLIB_INCLUDE_DIR}) +find_library(ZXCVBN_LIBRARIES zxcvbn) +if(NOT ZXCVBN_LIBRARIES) + add_subdirectory(src/thirdparty/zxcvbn) + set(ZXCVBN_LIBRARIES zxcvbn) +endif(NOT ZXCVBN_LIBRARIES) + add_subdirectory(src) add_subdirectory(share) if(WITH_TESTS) diff --git a/COPYING b/COPYING index 6baf4c27e..a00aaf28c 100644 --- a/COPYING +++ b/COPYING @@ -137,10 +137,12 @@ Files: share/icons/badges/2_Expired.svg share/icons/database/C46_Help.svg share/icons/database/C53_Apply.svg share/icons/database/C61_Services.svg + share/icons/application/scalable/actions/proton.svg Copyright: 2022 KeePassXC Team License: MIT Files: share/icons/application/scalable/actions/application-exit.svg + share/icons/application/scalable/actions/arrow-collapse-down.svg share/icons/application/scalable/actions/attributes-copy.svg share/icons/application/scalable/actions/auto-type.svg share/icons/application/scalable/actions/bitwarden.svg @@ -155,6 +157,7 @@ Files: share/icons/application/scalable/actions/application-exit.svg share/icons/application/scalable/actions/database-lock-all.svg share/icons/application/scalable/actions/database-merge.svg share/icons/application/scalable/actions/database-search.svg + share/icons/application/scalable/actions/database-settings.svg share/icons/application/scalable/actions/dialog-close.svg share/icons/application/scalable/actions/dialog-ok.svg share/icons/application/scalable/actions/document-close.svg @@ -175,6 +178,7 @@ Files: share/icons/application/scalable/actions/application-exit.svg share/icons/application/scalable/actions/entry-delete.svg share/icons/application/scalable/actions/entry-restore.svg share/icons/application/scalable/actions/entry-edit.svg + share/icons/application/scalable/actions/entry-expire.svg share/icons/application/scalable/actions/entry-new.svg share/icons/application/scalable/actions/favicon-download.svg share/icons/application/scalable/actions/fingerprint.svg @@ -203,6 +207,7 @@ Files: share/icons/application/scalable/actions/application-exit.svg share/icons/application/scalable/actions/password-show-on.svg share/icons/application/scalable/actions/qrcode.svg share/icons/application/scalable/actions/refresh.svg + share/icons/application/scalable/actions/remote-sync.svg share/icons/application/scalable/actions/reports.svg share/icons/application/scalable/actions/reports-exclude.svg share/icons/application/scalable/actions/sort-alphabetical-ascending.svg @@ -218,6 +223,7 @@ Files: share/icons/application/scalable/actions/application-exit.svg share/icons/application/scalable/actions/totp-copy.svg share/icons/application/scalable/actions/totp-copy-password.svg share/icons/application/scalable/actions/totp-edit.svg + share/icons/application/scalable/actions/totp-invalid.svg share/icons/application/scalable/actions/trash.svg share/icons/application/scalable/actions/url-copy.svg share/icons/application/scalable/actions/user-guide.svg @@ -239,9 +245,12 @@ Files: share/icons/application/scalable/actions/application-exit.svg share/icons/application/scalable/status/dialog-information.svg share/icons/application/scalable/status/dialog-warning.svg share/icons/application/scalable/status/security-high.svg -Copyright: 2019 Austin Andrews -License: SIL OPEN FONT LICENSE Version 1.1 -Comment: Taken from Material Design icon set (https://github.com/templarian/MaterialDesign/) + share/icons/application/scalable/actions/lock-open-alert.svg + share/icons/application/scalable/actions/lock-open.svg + share/icons/application/scalable/actions/lock.svg +Copyright: 2023 Pictogrammers +License: Apache-2.0 +Comment: Some icons are modified to fit KeePassXC design (https://pictogrammers.com/library/mdi/) Files: src/streams/qtiocompressor.* src/streams/QtIOCompressor @@ -249,7 +258,7 @@ Files: src/streams/qtiocompressor.* Copyright: 2009-2012, Nokia Corporation and/or its subsidiary(-ies) License: LGPL-2.1 or GPL-3 -Files: src/zxcvbn/zxcvbn.* +Files: src/thirdparty/zxcvbn/zxcvbn.* Copyright: 2015-2017, Tony Evans License: MIT diff --git a/INSTALL.md b/INSTALL.md index da62ffb88..e83f064c0 100644 --- a/INSTALL.md +++ b/INSTALL.md @@ -67,9 +67,9 @@ Note: These steps place the compiled KeePassXC binary inside the `./build/src/` ## MacOS Build Notes -If you installed Qt5 via Homebrew and CMake fails to find your Qt installation, you can specify it manually by adding the following parameter: +If you installed Qt@5 via Homebrew and CMake fails to find your Qt installation, you can specify it manually by adding the following parameter: -`-DCMAKE_PREFIX_PATH=$(brew --prefix qt5)/lib/cmake` +`-DCMAKE_PREFIX_PATH=$(brew --prefix qt@5)/lib/cmake` When building with ASAN support on macOS, you need to use `export ASAN_OPTIONS=detect_leaks=0` before running the tests (LSAN is no supported on macOS). diff --git a/README.md b/README.md index 0142a698b..c541afe80 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,5 @@ -# KeePassXC +# KeePassXC +[![OpenSSF Best Practices](https://bestpractices.coreinfrastructure.org/projects/6326/badge)](https://bestpractices.coreinfrastructure.org/projects/6326) [![TeamCity Build Status](https://ci.keepassxc.org/app/rest/builds/buildType:\(project:KeepassXC\)/statusIcon)](https://ci.keepassxc.org/?guest=1) [![codecov](https://codecov.io/gh/keepassxreboot/keepassxc/branch/develop/graph/badge.svg)](https://codecov.io/gh/keepassxreboot/keepassxc) [![GitHub release](https://img.shields.io/github/release/keepassxreboot/keepassxc)](https://github.com/keepassxreboot/keepassxc/releases/) @@ -21,12 +22,13 @@ KeePassXC has numerous features for novice and power users alike. Our goal is to * Password generator * Auto-Type passwords into applications * Browser integration with Google Chrome, Mozilla Firefox, Microsoft Edge, Chromium, Vivaldi, Brave, and Tor-Browser +* Support for passkeys using the browser integration * Entry icon download -* Import databases from CSV, 1Password, and KeePass1 formats +* Import databases from CSV, 1Password, Bitwarden, Proton Pass, and KeePass1 formats ### Advanced * Database reports (password health, HIBP, and statistics) -* Database export to CSV and HTML formats +* Database export to CSV, XML, and HTML formats * TOTP storage and generation * Field references between entries * File attachments and custom attributes @@ -54,6 +56,10 @@ You may directly contribute your own code by submitting a pull request. Please r Contributors are required to adhere to the project's [Code of Conduct](CODE-OF-CONDUCT.md). +## Generative AI + +Generative AI is fast becoming a first-party feature in most development environments, including GitHub itself. If the majority of a code submission is made using Generative AI (e.g., agent-based or vibe coding) then **we will document that in the pull request.** All code submissions go through a rigorous review process regardless of the development workflow or submitter. + ## License KeePassXC code is licensed under GPL-2 or GPL-3. Additional licensing for third-party files is detailed in [COPYING](./COPYING). diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 000000000..8f07bece0 --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,46 @@ +### Reporting Security Issues + +The KeePassXC team takes security vulnerabilities very seriously and appreciates your responsible disclosure efforts. We will make every effort to acknowledge your contributions and handle them promptly. + +To report a security issue, please use one of the following methods: + +- **GitHub Security Advisory:** Use the ["Report a Vulnerability"](https://github.com/keepassxreboot/keepassxc/security/advisories/new) tab on our GitHub repository. +- **Private Matrix Message:** Contact any of the following KeePassXC team members privately (also encrypted): + - [@droidmonkey_kpxc](https://matrix.to/#/@droidmonkey_kpxc:matrix.org) + - [@varjolintu](https://matrix.to/#/@varjolintu:matrix.org) + - [@phoerious](https://matrix.to/#/@phoerious:matrix.org) +- **Send an Email:** Send your report to team@keepassxc.org. We recommend encrypting the email if possible. + +Please **DO NOT** use public channels (e.g., GitHub issues, Matrix chat channels) for initial reporting of bona fide security vulnerabilities. + +Once you report a security issue, our team will respond with the next steps. After our initial reply, we will keep you informed of the progress towards a fix and full announcement. We may ask for additional information or guidance during this process. If we disagree that your report constitutes a genuine security vulnerability, we will inform you and close the report. Your report may be turned into an issue for further tracking. + +If you discover vulnerabilities in third-party modules used by KeePassXC, please report them to the maintainers of the respective modules. If the vulnerability impacts KeePassXC directly, we encourage you to notify us using the above methods. We will validate if the vulnerability is exploitable from KeePassXC code; please note that not all vulnerabilities are actually exploitable and do not constitute an immediate concern for the KeePassXC application. + +### Example Security Vulnerabilities + +When reporting, please ensure the issue falls under what can be considered a genuine security vulnerability for KeePassXC. Some examples include: + +- Unauthorized access to sensitive user data (e.g., passwords). +- Remote code execution or escalation of privileges. +- Bypassing authentication or encryption mechanisms. +- Broken or improperly implemented encryption methods. + +### Counter Examples + +The following issues are **not** considered security vulnerabilities: + +- Bugs caused by locally modifying the application (e.g., injecting DLLs, altering code). +- Crashes or misbehavior resulting from normal use (report this as a normal issue). +- Vulnerabilities found in third-party modules (should be reported to the module’s maintainers). + +### CVE Reporting Policy + +Please **DO NOT** submit a report to a Common Vulnerabilities and Exposures (CVE) Numbering Authority (CNA) before confirming the security vulnerability with the KeePassXC team. If we do not respond to your report within 30 days, this restriction no longer applies. + + +### Other Communication + +For other inquiries (e.g., developer questions, user questions), please use the public channels on Matrix: +- **User's Channel:** [#keepassxc:mozilla.org](https://matrix.to/#/#keepassxc:mozilla.org) +- **Developer's Channel:** [#keepassxc-dev:mozilla.org](https://matrix.to/#/#keepassxc-dev:mozilla.org) diff --git a/cmake/CLangFormat.cmake b/cmake/CLangFormat.cmake index b2df97d4d..9ddc4edb2 100644 --- a/cmake/CLangFormat.cmake +++ b/cmake/CLangFormat.cmake @@ -16,9 +16,8 @@ set(EXCLUDED_DIRS # third-party directories src/thirdparty - src/zxcvbn # objective-c directories - src/touchid + src/quickunlock/touchid src/autotype/mac src/gui/osutils/macutils) diff --git a/cmake/FindPCSC.cmake b/cmake/FindPCSC.cmake index ae3265fff..d37b269df 100644 --- a/cmake/FindPCSC.cmake +++ b/cmake/FindPCSC.cmake @@ -21,16 +21,38 @@ endif() if(NOT PCSC_FOUND) # Search for PC/SC headers on Mac and Windows + + # Additional search paths for Windows if not running in Visual Studio environment + if (WIN32) + # Resolve the ambiguity of using two names for one architechture + if(CMAKE_SYSTEM_PROCESSOR STREQUAL "AMD64" OR CMAKE_SYSTEM_PROCESSOR STREQUAL "x64") + set(ARCH_DIR "x64") + else() + set(ARCH_DIR "${CMAKE_SYSTEM_PROCESSOR}") + endif() + + # Locate Windows SDK Paths + if (CMAKE_WINDOWS_KITS_10_DIR) + set(WINSDKROOTC_INCLUDE "${CMAKE_WINDOWS_KITS_10_DIR}/Include/${CMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION}/um") + set(WINSDKROOTC_LIB "${CMAKE_WINDOWS_KITS_10_DIR}/LIB/${CMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION}/um/${ARCH_DIR}") + else() + set(WINSDKROOTC_INCLUDE "$ENV{ProgramFiles\(x86\)}/Windows Kits/10/Include/${CMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION}/um") + set(WINSDKROOTC_LIB "$ENV{ProgramFiles\(x86\)}/Windows Kits/10/LIB/${CMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION}/um/${ARCH_DIR}") + endif() + endif() + find_path(PCSC_INCLUDE_DIRS winscard.h HINTS - ${CMAKE_C_IMPLICIT_INCLUDE_DIRECTORIES} - /usr/include/PCSC + ${CMAKE_C_IMPLICIT_INCLUDE_DIRECTORIES} + /usr/include/PCSC + ${WINSDKROOTC_INCLUDE} PATH_SUFFIXES PCSC) # MAC library is PCSC, Windows library is WinSCard find_library(PCSC_LIBRARIES NAMES pcsclite libpcsclite WinSCard PCSC HINTS - ${CMAKE_C_IMPLICIT_LINK_DIRECTORIES}) + ${CMAKE_C_IMPLICIT_LINK_DIRECTORIES} + ${WINSDKROOTC_LIB}) endif() include(FindPackageHandleStandardArgs) diff --git a/cmake/KPXCMacDeployHelpers.cmake b/cmake/KPXCMacDeployHelpers.cmake index d22051d32..f86067cbc 100644 --- a/cmake/KPXCMacDeployHelpers.cmake +++ b/cmake/KPXCMacDeployHelpers.cmake @@ -1,5 +1,5 @@ # Running macdeployqt on a POST_BUILD copied binaries is pointless when using CPack because -# the copied binaries will be overriden by the corresponding install(TARGETS) commands. +# the copied binaries will be overridden by the corresponding install(TARGETS) commands. # That's why we run macdeployqt using install(CODE) on the already installed binaries. # The precondition is that all install(TARGETS) calls have to be called before this function is # called. diff --git a/codecov.yaml b/codecov.yaml index d92656b6f..96ac133ef 100644 --- a/codecov.yaml +++ b/codecov.yaml @@ -1,8 +1,27 @@ +codecov: + require_ci_to_pass: false coverage: range: 60..80 round: nearest precision: 2 + status: + project: + default: + target: auto + threshold: 0.5% + paths: + - "src" + patch: + default: + target: 50% + threshold: 0% + informational: true + paths: + - "src" fixes: - "*/src/::" +ignore: + - "src/gui/styles/**" + - "src/thirdparty/**" comment: require_changes: true diff --git a/docs/GettingStarted.adoc b/docs/GettingStarted.adoc index 5135e09e2..08d331ba0 100644 --- a/docs/GettingStarted.adoc +++ b/docs/GettingStarted.adoc @@ -7,6 +7,7 @@ KeePassXC Team :imagesdir: images :stylesheet: styles/dark.css :toc: left +:experimental: ifdef::backend-pdf[] :title-page: :title-logo-image: {imagesdir}/kpxc_logo.png @@ -26,8 +27,8 @@ include::topics/DownloadInstall.adoc[tags=*;!advanced] include::topics/UserInterface.adoc[tags=*;!advanced] -include::topics/PasswordGenerator.adoc[tags=*;!advanced] - include::topics/DatabaseOperations.adoc[tags=*;!advanced] -include::topics/BrowserPlugin.adoc[tags=*;!advanced] +include::topics/PasswordGenerator.adoc[tags=*;!advanced] + +include::topics/BrowserIntegration.adoc[tags=*;!advanced] diff --git a/docs/UserGuide.adoc b/docs/UserGuide.adoc index 2ebd77793..ec13940ca 100644 --- a/docs/UserGuide.adoc +++ b/docs/UserGuide.adoc @@ -6,6 +6,8 @@ KeePassXC Team :imagesdir: images :stylesheet: styles/dark.css :toc: left +:sectanchors: +:experimental: ifdef::backend-pdf[] :title-page: :title-logo-image: {imagesdir}/kpxc_logo.png @@ -23,18 +25,18 @@ include::topics/UserInterface.adoc[tags=*] include::topics/DatabaseOperations.adoc[tags=*] -include::topics/ImportExport.adoc[tags=*] - include::topics/PasswordGenerator.adoc[tags=*] -include::topics/BrowserPlugin.adoc[tags=*] +include::topics/ImportExport.adoc[tags=*] + +include::topics/KeeShare.adoc[tags=*] + +include::topics/BrowserIntegration.adoc[tags=*] include::topics/Passkeys.adoc[tags=*] include::topics/AutoType.adoc[tags=*] -include::topics/KeeShare.adoc[tags=*] - include::topics/SSHAgent.adoc[tags=*] include::topics/Reference.adoc[tags=*] diff --git a/docs/images/browser_custom_browser_configuration.png b/docs/images/browser_custom_browser_configuration.png new file mode 100644 index 000000000..257c571f1 Binary files /dev/null and b/docs/images/browser_custom_browser_configuration.png differ diff --git a/docs/images/browser_extension_icons.png b/docs/images/browser_extension_icons.png index e4fb1d8a3..f8430265e 100644 Binary files a/docs/images/browser_extension_icons.png and b/docs/images/browser_extension_icons.png differ diff --git a/docs/images/database_security_encryption.png b/docs/images/database_security_encryption.png index 3718cd19f..aa2721421 100644 Binary files a/docs/images/database_security_encryption.png and b/docs/images/database_security_encryption.png differ diff --git a/docs/images/database_security_encryption_advanced.png b/docs/images/database_security_encryption_advanced.png index deb112ac1..617c61fd6 100644 Binary files a/docs/images/database_security_encryption_advanced.png and b/docs/images/database_security_encryption_advanced.png differ diff --git a/docs/images/database_settings.png b/docs/images/database_settings.png index ebc713560..adf2b48e2 100644 Binary files a/docs/images/database_settings.png and b/docs/images/database_settings.png differ diff --git a/docs/images/database_view.png b/docs/images/database_view.png index bf273c12f..77b655741 100644 Binary files a/docs/images/database_view.png and b/docs/images/database_view.png differ diff --git a/docs/images/export_database.png b/docs/images/export_database.png index 8f7f7b994..fd423ccee 100644 Binary files a/docs/images/export_database.png and b/docs/images/export_database.png differ diff --git a/docs/images/main_interface.png b/docs/images/main_interface.png index d598e4743..32f43cad6 100644 Binary files a/docs/images/main_interface.png and b/docs/images/main_interface.png differ diff --git a/docs/images/new_db_wizard_2.png b/docs/images/new_db_wizard_2.png index 02191c665..98331ad13 100644 Binary files a/docs/images/new_db_wizard_2.png and b/docs/images/new_db_wizard_2.png differ diff --git a/docs/images/open_database.png b/docs/images/open_database.png index e14841fe8..0c4391856 100644 Binary files a/docs/images/open_database.png and b/docs/images/open_database.png differ diff --git a/docs/images/save_database_backup.png b/docs/images/save_database_backup.png index c453de34b..b59122642 100644 Binary files a/docs/images/save_database_backup.png and b/docs/images/save_database_backup.png differ diff --git a/docs/images/sync_remote_settings.png b/docs/images/sync_remote_settings.png new file mode 100644 index 000000000..1d5c006b3 Binary files /dev/null and b/docs/images/sync_remote_settings.png differ diff --git a/docs/images/theme_selection.png b/docs/images/theme_selection.png index 0a67e2e4e..3f87719d3 100644 Binary files a/docs/images/theme_selection.png and b/docs/images/theme_selection.png differ diff --git a/docs/images/toolbar.png b/docs/images/toolbar.png index ed5c1c803..742379983 100644 Binary files a/docs/images/toolbar.png and b/docs/images/toolbar.png differ diff --git a/docs/images/unlock_database.png b/docs/images/unlock_database.png index 953cbf51e..e8a5c19d2 100644 Binary files a/docs/images/unlock_database.png and b/docs/images/unlock_database.png differ diff --git a/docs/images/welcome_screen.png b/docs/images/welcome_screen.png index bb6ea742c..a00ae400f 100644 Binary files a/docs/images/welcome_screen.png and b/docs/images/welcome_screen.png differ diff --git a/docs/man/keepassxc.1.adoc b/docs/man/keepassxc.1.adoc index 16e10de9c..b82a97b03 100644 --- a/docs/man/keepassxc.1.adoc +++ b/docs/man/keepassxc.1.adoc @@ -28,26 +28,38 @@ keepassxc - a modern open-source password manager *keepassxc* [_options_] [_filename(s)_] == DESCRIPTION -*KeePassXC* is a free/open-source password manager or safe which helps you to manage your passwords in a secure way. -The complete database is always encrypted with the industry-standard AES (alias Rijndael) encryption algorithm using a 256 bit key. +*KeePassXC* is a free/open-source password manager or safe which helps you to manage your passwords securely. +The complete database is always encrypted with the industry-standard AES (also known as Rijndael) encryption algorithm using a 256-bit key. KeePassXC uses a database format that is compatible with KeePass Password Safe. -Your wallet works offline and requires no Internet connection. +Your database works offline and requires no internet connection. == OPTIONS *-h*, *--help*:: Displays this help. +*--help-all*:: + Displays help including Qt specific options. + *-v*, *--version*:: Displays version information. *--config* <__config__>:: Path to a custom config file. +*--localconfig* <__localconfig__>:: + Path to a custom local config file. + +*--lock*:: + Locks all open databases. + *--keyfile* <__keyfile__>:: Key file of the database. *--pw-stdin*:: - Read password of the database from stdin. + Reads password of the database from stdin. + +*--minimized*:: + Starts KeePassXC minimized to the system tray. *--debug-info*:: Displays debugging information. diff --git a/docs/styles/dark.css b/docs/styles/dark.css index 8f7bd67b6..4295629f4 100644 --- a/docs/styles/dark.css +++ b/docs/styles/dark.css @@ -180,7 +180,7 @@ body.toc2.toc-right{padding-left:0;padding-right:20em}} .sect1{padding-bottom:1.25em}} .sect1:last-child{padding-bottom:0} .sect1+.sect1{border-top:1px solid #efefed} -#content h1>a.anchor,h2>a.anchor,h3>a.anchor,#toctitle>a.anchor,.sidebarblock>.content>.title>a.anchor,h4>a.anchor,h5>a.anchor,h6>a.anchor{position:absolute;z-index:1001;width:1.5ex;margin-left:-1.5ex;display:block;text-decoration:none!important;visibility:hidden;text-align:center;font-weight:400} +#content h1>a.anchor,h2>a.anchor,h3>a.anchor,#toctitle>a.anchor,.sidebarblock>.content>.title>a.anchor,h4>a.anchor,h5>a.anchor,h6>a.anchor{position:absolute;z-index:1001;width:2.0ex;margin-left:-1.8ex;margin-top:0.08ex;display:block;text-decoration:none!important;visibility:hidden;text-align:center;font-weight:400} #content h1>a.anchor::before,h2>a.anchor::before,h3>a.anchor::before,#toctitle>a.anchor::before,.sidebarblock>.content>.title>a.anchor::before,h4>a.anchor::before,h5>a.anchor::before,h6>a.anchor::before{content:"\00A7";font-size:.85em;display:block;padding-top:.1em} #content h1:hover>a.anchor,#content h1>a.anchor:hover,h2:hover>a.anchor,h2>a.anchor:hover,h3:hover>a.anchor,#toctitle:hover>a.anchor,.sidebarblock>.content>.title:hover>a.anchor,h3>a.anchor:hover,#toctitle>a.anchor:hover,.sidebarblock>.content>.title>a.anchor:hover,h4:hover>a.anchor,h4>a.anchor:hover,h5:hover>a.anchor,h5>a.anchor:hover,h6:hover>a.anchor,h6>a.anchor:hover{visibility:visible} #content h1>a.link,h2>a.link,h3>a.link,#toctitle>a.link,.sidebarblock>.content>.title>a.link,h4>a.link,h5>a.link,h6>a.link{color:#ba3925;text-decoration:none} diff --git a/docs/topics/.sharedheader b/docs/topics/.sharedheader index c639a39be..7a72b03a7 100644 --- a/docs/topics/.sharedheader +++ b/docs/topics/.sharedheader @@ -4,3 +4,4 @@ KeePassXC Team :stylesheet: ../styles/dark.css :icons: font :toc: left +:experimental: diff --git a/docs/topics/AutoType.adoc b/docs/topics/AutoType.adoc index 04c5e7b96..f4bab1262 100644 --- a/docs/topics/AutoType.adoc +++ b/docs/topics/AutoType.adoc @@ -24,20 +24,20 @@ You can also set the time to remember the last used entry between presses of the === Configure Auto-Type Sequences Each entry in your database can have multiple Auto-Type sequences associated with various window titles. Simulated key presses can be sent to any other currently open window of your choice (web browser windows, login dialogs boxes, and so on). When the Global Auto-Type hotkey is pressed, KeePassXC will search your database for entries matching the current selected window title. -NOTE: The default Auto-Type sequence is `{USERNAME}{TAB}{PASSWORD}{ENTER}`. This means that it first types the username of the selected entry, then presses the `Tab` key, then types the password of the entry and finally presses the `Enter` key. +NOTE: The default Auto-Type sequence is `{USERNAME}{TAB}{PASSWORD}{ENTER}`. This means that it first types the username of the selected entry, then presses the kbd:[Tab] key, then types the password of the entry and finally presses the kbd:[Enter] key. TIP: To change the default Auto-Type sequence for all entries of your database, edit the root (top-most) group of your database and set a specific sequence. Child groups and entries will inherit this sequence by default. To configure Auto-Type sequences for your entries, perform the following steps: -1. Navigate to the entries list and open the desired entry for editing. Click the _Auto-Type_ item from the left-hand menu bar *(1)*. Press the `+` button *(2)* to add a new sequence entry. Select the desired window using the drop-down menu, or simply type a window title in the box *(3)*. +1. Navigate to the entries list and open the desired entry for editing. Click the _Auto-Type_ item from the left-hand menu bar *(1)*. Press the kbd:[+] button *(2)* to add a new sequence entry. Select the desired window using the drop-down menu, or simply type a window title in the box *(3)*. + TIP: You can use an asterisk (`\*`) to match any value (e.g., when a window title contains a dynamic filename or website name). Set the window title to `*` to match all windows. Leave the window title blank to offer additional default Auto-Type sequences, such as custom attributes. + .Auto-Type entry sequences image::autotype_entry_sequences.png[] -2. _(Optional)_ Define a custom Auto-Type sequence for each window title match by selecting the _Use specific sequence for this association_ checkbox. Sequence action codes and field placeholders are detailed in the following table. Beyond the most important ones detailed below, there are additional action codes and placeholders available: xref:UserGuide.adoc#_auto_type_actions[Auto-Type Actions Reference] and xref:UserGuide.adoc#_entry_placeholders[Entry Placeholders Reference]. Action codes and placeholders are not case sensitive. +2. _(Optional)_ Define a custom Auto-Type sequence for each window title match by selecting the _Use specific sequence for this association_ checkbox. Sequence action codes and field placeholders are detailed in the following table. Beyond the most important ones detailed below, there are additional action codes and placeholders available: <> and <>. Action codes and placeholders are not case sensitive. + [grid=rows, frame=none, width=90%] |=== @@ -60,7 +60,7 @@ image::autotype_entry_sequences.png[] |Press the corresponding keyboard key |{UP}, {DOWN}, {LEFT}, {RIGHT} |Press the corresponding arrow key -|{LEFTBRACE}, {RIGHTBRACE} |Press `{` or `}`, respectively +|{LEFTBRACE}, {RIGHTBRACE} |Press kbd:[{] or kbd:[}], respectively |{<KEY> X} |Repeat <KEY> X times (e.g., {SPACE 5} inserts five spaces) |{DELAY=X} |Set delay between key presses to X milliseconds |{DELAY X} |Pause typing for X milliseconds @@ -89,7 +89,7 @@ When you press the global Auto-Type hotkey, KeePassXC searches all unlocked data .Auto-Type sequence selection image::autotype_selection_dialog.png[,70%] -Perform the selected Auto-Type sequence by double clicking the desired row or pressing _Enter_. Press the up and down arrows to navigate the list. Sequences can be filtered through the text edit field. +Perform the selected Auto-Type sequence by double clicking the desired row or pressing kbd:[Enter]. Press the up and down arrows to navigate the list. Sequences can be filtered through the text edit field. .Auto-Type search database image::autotype_selection_dialog_search.png[,70%] @@ -104,7 +104,7 @@ The option to type just the username, password, or current TOTP value is availab TIP: On Windows, you will see an option to use a virtual keyboard in this sub-menu. This is an experimental feature that allows you to type into virtual machines by simulating actual keyboard presses. Some international keyboards may be unsupported due to limitations in the Windows API. === Performing Entry-Level Auto-Type -You can quickly activate the default Auto-Type sequence for a particular entry using Entry-Level Auto-Type. For this operation, the KeePassXC window will be minimized and the Auto-Type sequence occurs in the previously selected window. You can perform Entry-Level Auto-Type from the toolbar icon *(A)*, entry context menu *(B)*, or by pressing `Ctrl+Shift+V`. +You can quickly activate the default Auto-Type sequence for a particular entry using Entry-Level Auto-Type. For this operation, the KeePassXC window will be minimized and the Auto-Type sequence occurs in the previously selected window. You can perform Entry-Level Auto-Type from the toolbar icon *(A)*, entry context menu *(B)*, or by pressing kbd:[Ctrl+Shift+V]. WARNING: Be careful when using Entry-Level Auto-Type as you can inadvertently type into the wrong window. For example, a chat window or email. diff --git a/docs/topics/BrowserPlugin.adoc b/docs/topics/BrowserIntegration.adoc similarity index 68% rename from docs/topics/BrowserPlugin.adoc rename to docs/topics/BrowserIntegration.adoc index f36767492..c1650fa4b 100644 --- a/docs/topics/BrowserPlugin.adoc +++ b/docs/topics/BrowserIntegration.adoc @@ -1,158 +1,201 @@ -= KeePassXC – Browser Plugin -include::.sharedheader[] -:imagesdir: ../images - -// tag::content[] -== Setup Browser Integration -The KeePassXC-Browser extension is installed within your web browser so that you can automatically pull usernames and passwords from KeePassXC and populate them directly into website fields. It is a very useful and secure extension that enhances your productivity while using KeePassXC. With this extension, you do not need to manually copy the data from your KeePassXC database and paste it into the website fields. - -The KeePassXC-Browser extension is available on the following web browsers: - -* Google Chrome, Vivaldi, and Brave -* Mozilla Firefox and Tor-Browser -* Microsoft Edge -* Chromium - -=== Install the Browser Extension -You can download the KeePassXC-Browser extension from your web browser. To download the KeePassXC-Browser extension, perform the following steps: - -1. Click the link corresponding to your browser: - * https://chrome.google.com/webstore/detail/keepassxc-browser/oboonakemofpalcgghocfoadofidjkkk[Chrome, Chromium, Vivaldi, and Brave] - * https://addons.mozilla.org/en-US/firefox/addon/keepassxc-browser[Mozilla Firefox and Tor-Browser] - * https://microsoftedge.microsoft.com/addons/detail/keepassxcbrowser/pdffhmdngciaglkoonimfcmckehcpafo[Microsoft Edge] - -2. Click the button to install/add the extension to the browser. Accept any confirmation dialogs. - -TIP: For the most up-to-date troubleshooting advice on all platforms, please read our https://github.com/keepassxreboot/keepassxc-browser/wiki/Troubleshooting-guide[Troubleshooting Guide]. - -// tag::advanced[] -NOTE: When Microsoft Edge is installed as a managed application, system administrators are required to deploy a custom native messaging configuration. Instructions for this are found in the advanced section below. -// end::advanced[] - -=== Configure KeePassXC-Browser -To start using KeePassXC-Browser, you must configure it so that it can communicate with the KeePassXC application on your desktop. - -To configure KeePassXC-Browser, perform the following steps: - -1. Open the KeePassXC application on your desktop and navigate to Tools > Settings. - -2. Click the Browser Integration option on the left-hand side *(1)*. The following screen appears: -+ -.Browser Settings -image::browser_settings.png[] - -3. Click the _Enable browser integration_ checkbox *(2)*. Then select the browsers for which you have downloaded the KeePassXC-Browser extension *(3)* and click *OK*. - -4. Ensure your database is unlocked, then open (or restart) your browser. - -5. Click the KeePassXC-Browser extension icon *(A)* in your browser (see figure below). A pop-up window appears. -+ -.Connect Extension to KeePassXC -image::browser_extension_connect.png[,80%] - -6. Click the _Connect_ button *(B)* in the pop-up window to complete integrating the KeePassXC-Browser extension with your KeePassXC desktop application. - -7. You are now prompted to enter a unique name to identify the connection between this browser and your database. Enter a unique name in the field (e.g., firefox-laptop) and click the _Save and allow access_ button. -+ -.Extension Association Dialog -image::browser_extension_association.png[,80%] - -WARNING: If you reuse a connection name in a database, the previous browser connection will be overwritten and prevent access. - -=== Using the Browser Extension -The KeePassXC-Browser extension lets you automatically populate the entries from your KeePassXC database into the fields on websites you visit. To do so, perform the following steps: - -1. Open your KeePassXC desktop application and unlock your database. - -2. Open your web browser. The KeePassXC-Browser extension icon in your browser window will change based on its connection state. The figure below shows the different states. -+ -*(A)* KeePassXC is not running or is disconnected + -*(B)* Connected to KeePassXC, but database is locked + -*\(C)* Connected to KeePassXC and ready to use -+ -.Extension Icon States -image::browser_extension_icons.png[,70%] - -3. If the KeePassXC desktop application is not connected with the KeePassXC-Browser extension, click the extension icon in your web browser and click _Reload_ from the pop-up window as shown in the following screen. -+ -.Reload Extension Connection -image::browser_extension_reload.png[,80%] - -4. Open the URL for which you want to use with your database. If you have previously created an entry in your database then the KeePassXC-Browser Confirm Access dialog may appear: -+ -.Confirm Access Dialog -image::browser_confirm_access_dialog.png[,80%] - -5. Ensure the credentials you want to use are checked, then click *(A)* Remember _(optional)_, then click _Allow Selected_ *(B)*. - -6. In your website, the KeePassXC icon will appear in the username field of the login form *(A)*. Click the icon to populate the field with your stored credentials. If you have more than one credential for this website, a dropdown will appear to choose the one to use. -+ -.Fill Credentials -image::browser_fill_credentials.png[,80%] - -// tag::advanced[] -=== Browser statistics -You can see a cross-section of all browser-related settings applied to entries within a database through the Browser Statistics report. To access these, use the _Database_ -> _Database reports..._ menu option then click on _Browser Statistics_ on the left-hand menu. From here you can see all entries with URLs applied to them, explicitly allowed and denied URLs, and any entries with custom browser settings. - -.Browser statistics -image::browser_statistics.png[] - -=== Advanced Usage -You can configure unique browser integration behavior for each entry. This allows you to add multiple URLs to an entry, hide an entry from the browser integration, and more. To access these settings, open an entry for editing then click on _Browser Integration_ option in the left-hand menu *(1)*. - -After opening the settings you can add any number of additional URLs by clicking the _Add_ button *(2)* and typing the URL in the list to the left *(3)*. - -.Entry browser settings -image::browser_entry_settings.png[] - -To set options for all entries within a group, edit the group and go to the browser integration section *(1)*. Here you can explicitly disable access to all entries under a group hierarchy to the browser extension. You can set other useful options for groups of entries as well. - -.Group browser settings -image::browser_group_settings.png[] - -Database-wide operations are available in the database settings. To access these use the _Database_ -> _Database settings..._ menu option. Click on _Browser Integration_ on the left-hand menu. From here you can disconnect all browsers, convert legacy KeePass-HTTP settings, reset all entry-level settings, and refresh the database root group ID (useful when making copies of your database file). - -.Database browser settings -image::browser_database_settings.png[] - -Finally, advanced application-wide settings are available in the Browser Integration tab of the application settings. - -WARNING: We do not recommend changing any of these settings as they may break the browser integration plugin. - -.Advanced browser settings -image::browser_advanced_settings.png[] - -=== Advanced Setup -==== Managed Microsoft Edge on Windows -1. Deploy *org.keepassxc.keepassxc_browser_edge.json* to, for example, `C:\ProgramData\KeepassXC` on all managed platforms. -+ ----- -{ - "allowed_origins": [ - "chrome-extension://pdffhmdngciaglkoonimfcmckehcpafo/" - ], - "description": "KeePassXC integration with native messaging support", - "name": "org.keepassxc.keepassxc_browser", - "path": "C:\\Program Files\\KeePassXC\\keepassxc-proxy.exe", - "type": "stdio" -} ----- - -2. Configure GPO options (registry result): -+ ----- -Windows Registry Editor Version 5.00 -[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Edge\NativeMessagingHosts\org.keepassxc.keepassxc_browser] -@="C:\ProgramData\KeepassXC\org.keepassxc.keepassxc_browser_edge.json" - -[HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Edge] -"NativeMessagingUserLevelHosts"=dword:00000000 - -[HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Edge\ExtensionInstallAllowlist] -"1"="pdffhmdngciaglkoonimfcmckehcpafo" - -[HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Edge\NativeMessagingAllowlist] -"1"="org.keepassxc.keepassxc_browser" ----- -// end::advanced[] -// end::content[] += KeePassXC – Browser Plugin +include::.sharedheader[] +:imagesdir: ../images + +// tag::content[] +== Browser Integration +The KeePassXC-Browser extension is installed within your web browser so that you can automatically pull usernames and passwords from KeePassXC and populate them directly into website fields. It is a very useful and secure extension that enhances your productivity while using KeePassXC. With this extension, you do not need to manually copy the data from your KeePassXC database and paste it into the website fields. + +The KeePassXC-Browser extension is available on the following web browsers: + +* Google Chrome, Vivaldi, and Brave +* Mozilla Firefox and Tor-Browser +* Microsoft Edge +* Chromium + +NOTE: On Linux, Flatpak and Snap based browsers are generally not supported. Ubuntu's Firefox Snap is currently the only known exception. + +=== Install the Browser Extension +You can download the KeePassXC-Browser extension from your web browser. To download the KeePassXC-Browser extension, perform the following steps: + +1. Click the link corresponding to your browser: + * https://chromewebstore.google.com/detail/keepassxc-browser/oboonakemofpalcgghocfoadofidjkkk[Chrome, Chromium, Vivaldi, and Brave] + * https://addons.mozilla.org/en-US/firefox/addon/keepassxc-browser[Mozilla Firefox and Tor-Browser] + * https://microsoftedge.microsoft.com/addons/detail/keepassxcbrowser/pdffhmdngciaglkoonimfcmckehcpafo[Microsoft Edge] + +2. Click the button to install/add the extension to the browser. Accept any confirmation dialogs. + +TIP: For the most up-to-date troubleshooting advice on all platforms, please read our https://github.com/keepassxreboot/keepassxc-browser/wiki/Troubleshooting-guide[Troubleshooting Guide]. + +// tag::advanced[] +NOTE: When Microsoft Edge is installed as a managed application, system administrators are required to deploy a custom native messaging configuration. Instructions for this are found in the advanced section below. +// end::advanced[] + +=== Configure KeePassXC-Browser +To start using KeePassXC-Browser, you must configure it so that it can communicate with the KeePassXC application on your desktop. + +To configure KeePassXC-Browser, perform the following steps: + +1. Open the KeePassXC application on your desktop and navigate to Tools > Settings. + +2. Click the Browser Integration option on the left-hand side *(1)*. The following screen appears: ++ +.Browser Settings +image::browser_settings.png[] + +3. Click the _Enable browser integration_ checkbox *(2)*. Then select the browsers for which you have downloaded the KeePassXC-Browser extension *(3)* and click *OK*. + +4. Ensure your database is unlocked, then open (or restart) your browser. + +5. Click the KeePassXC-Browser extension icon *(A)* in your browser (see figure below). A pop-up window appears. ++ +.Connect Extension to KeePassXC +image::browser_extension_connect.png[,80%] + +6. Click the _Connect_ button *(B)* in the pop-up window to complete integrating the KeePassXC-Browser extension with your KeePassXC desktop application. + +7. You are now prompted to enter a unique name to identify the connection between this browser and your database. Enter a unique name in the field (e.g., firefox-laptop) and click the _Save and allow access_ button. ++ +.Extension Association Dialog +image::browser_extension_association.png[,80%] + +WARNING: If you reuse a connection name in a database, the previous browser connection will be overwritten and prevent access. + +=== Using the Browser Extension +The KeePassXC-Browser extension lets you automatically populate the entries from your KeePassXC database into the fields on websites you visit. To do so, perform the following steps: + +1. Open your KeePassXC desktop application and unlock your database. + +2. Open your web browser. The KeePassXC-Browser extension icon in your browser window will change based on its connection state. The figure below shows the different states. ++ +*(A)* KeePassXC is not running or is disconnected. + +*(B)* KeePassXC is running, but KeePassXC Browser Extension is not connected to the current database. + +*\(C)* Connected to KeePassXC, but database is locked. + +*(D)* Connected to KeePassXC and ready to use. If the icon is shown with a number, it indicates the number of credentials found for the current site. ++ +.Extension Icon States +image::browser_extension_icons.png[,70%] + +3. If the KeePassXC desktop application is not connected with the KeePassXC-Browser extension, click the extension icon in your web browser and click _Reload_ from the pop-up window as shown in the following screen. ++ +.Reload Extension Connection +image::browser_extension_reload.png[,80%] + +4. Open the URL for which you want to use with your database. If you have previously created an entry in your database then the KeePassXC-Browser Confirm Access dialog may appear: ++ +.Confirm Access Dialog +image::browser_confirm_access_dialog.png[,80%] + +5. Ensure the credentials you want to use are checked, then click *(A)* Remember _(optional)_, then click _Allow Selected_ *(B)*. + +6. In your website, the KeePassXC icon will appear in the username field of the login form *(A)*. Click the icon to populate the field with your stored credentials. If you have more than one credential for this website, a dropdown will appear to choose the one to use. ++ +.Fill Credentials +image::browser_fill_credentials.png[,80%] + +=== Generate Passwords +The KeePassXC-Browser Extension also lets you generate passwords directly in your browser. +This feature can be used for websites with existing credentials as well as for new websites. +You can then choose to update/add the credentials to your KeePassXC database directly from the Browser. + +1. Ensure your database is unlocked and configured to use the Browser extension as shown above. + +2. Right click on a password field and from the KeePassXC sub-menu choose _Show Password Generator_. The standard KeePassXC password generator will appear. + +3. Configure the password generation options and click _Apply Password_ when done. The generated password will be filled into the previously selected field. + +4. When you have successfully submitted the password on the website, a popup will appear asking you to either update an existing entry or add a new one. + +// tag::advanced[] +=== Browser statistics +You can see a cross-section of all browser-related settings applied to entries within a database through the Browser Statistics report. To access these, use the _Database_ -> _Database reports..._ menu option then click on _Browser Statistics_ on the left-hand menu. From here you can see all entries with URLs applied to them, explicitly allowed and denied URLs, and any entries with custom browser settings. + +.Browser statistics +image::browser_statistics.png[] + +=== Advanced Usage +You can configure unique browser integration behavior for each entry. This allows you to add multiple URLs to an entry, hide an entry from the browser integration, and more. To access these settings, open an entry for editing then click on _Browser Integration_ option in the left-hand menu *(1)*. + +After opening the settings you can add any number of additional URLs by clicking the _Add_ button *(2)* and typing the URL in the list to the left *(3)*. + +Additional URLs also supports wildcards (with KeePassXC 2.7.10 and later). You can use URLs like: +---- +https://*.example.com +https://example.com/*/path +https://sub.*.example.com/path/* +---- + +.Entry browser settings +image::browser_entry_settings.png[] + +To set options for all entries within a group, edit the group and go to the browser integration section *(1)*. Here you can explicitly disable access to all entries under a group hierarchy to the browser extension. You can set other useful options for groups of entries as well. + +.Group browser settings +image::browser_group_settings.png[] + +Database-wide operations are available in the database settings. To access these use the _Database_ -> _Database settings..._ menu option. Click on _Browser Integration_ on the left-hand menu. From here you can disconnect all browsers, convert legacy KeePass-HTTP settings, reset all entry-level settings, and refresh the database root group ID (useful when making copies of your database file). + +.Database browser settings +image::browser_database_settings.png[] + +Finally, advanced application-wide settings are available in the Browser Integration tab of the application settings. + +WARNING: We do not recommend changing any of these settings as they may break the browser integration plugin. + +.Advanced browser settings +image::browser_advanced_settings.png[] + +=== Advanced Setup +==== Custom Browser option +It is possible to enable support for a custom browser (e.g. LibreWolf, WaterFox, Arc, beta and nightly browsers, etc.) using this feature. +This feature is only available for Linux and macOS. + +.Custom browser configuration +image::browser_custom_browser_configuration.png[] + +The native messaging script file needed for the custom browser depends on the browser type. For Firefox based browsers like Librefox the _Browser type_ must be _Firefox_. For Arc, Opera, etc. the type must be set to _Chromium_. + +_Config location_ must have the exact path for the browser's _native-messaging-hosts_ folder. If you are unsure, refer to our https://github.com/keepassxreboot/keepassxc-browser/wiki/Troubleshooting-guide#1-after-enabling-browser-integration-and-support-for-your-browser[Troubleshooting Guide] for listing of the most common paths, and a few ways for finding a path when it's not known. + +When a Custom Browser has been successfully set, KeePassXC will automatically write the needed native messaging script file to the folder. + +If you wish to support multiple custom browsers, you can copy the native messaging script files manually to the _native-messaging-hosts_ folder from other browsers. + +==== Managed Microsoft Edge on Windows +1. Deploy *org.keepassxc.keepassxc_browser_edge.json* to, for example, `C:\ProgramData\KeePassXC\` on all managed platforms. ++ +---- +{ + "allowed_origins": [ + "chrome-extension://pdffhmdngciaglkoonimfcmckehcpafo/" + ], + "description": "KeePassXC integration with native messaging support", + "name": "org.keepassxc.keepassxc_browser", + "path": "C:\\Program Files\\KeePassXC\\keepassxc-proxy.exe", + "type": "stdio" +} +---- + +2. Configure GPO options (see https://learn.microsoft.com/en-us/deployedge/microsoft-edge-policies#native-messaging[Microsoft Edge Native Messaging Policies] for more information.): ++ +---- +Windows Registry Editor Version 5.00 +[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Edge\NativeMessagingHosts\org.keepassxc.keepassxc_browser] +@="C:\ProgramData\KeepassXC\org.keepassxc.keepassxc_browser_edge.json" + +[HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Edge] +"NativeMessagingUserLevelHosts"=dword:00000000 + +[HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Edge\ExtensionInstallAllowlist] +"1"="pdffhmdngciaglkoonimfcmckehcpafo" + +[HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Edge\NativeMessagingAllowlist] +"1"="org.keepassxc.keepassxc_browser" +---- + +==== Managed Microsoft Edge on macOS +1. Deploy *org.keepassxc.keepassxc_browser_edge.json* to `/Library/Microsoft/Edge/NativeMessagingHosts`. + +2. You may need to configure Edge to allowlist the extension and native messaging host. See https://learn.microsoft.com/en-us/deployedge/microsoft-edge-policies#native-messaging[Microsoft Edge Native Messaging Policies] for more information. +// end::advanced[] +// end::content[] diff --git a/docs/topics/DatabaseOperations.adoc b/docs/topics/DatabaseOperations.adoc index 35bcdbb16..c6a7fb4fc 100644 --- a/docs/topics/DatabaseOperations.adoc +++ b/docs/topics/DatabaseOperations.adoc @@ -36,6 +36,13 @@ NOTE: Keep this password for your database safe. Either memorize it or note it d 5. Click Done. You will be prompted to select a location to save your database file. The database file is saved on to your computer with the default `.kdbx` extension. You can store your database wherever you wish, it is fully encrypted at all times preventing unauthorized access. +=== Storing Your Database +The database file that you create might contain highly sensitive data and must be stored in a very secure way. You must make sure that the database is always protected with a strong and long password. The database file that is protected with a strong and long password is secure and encrypted while stored on your computer or cloud storage service. + +Make sure that you or someone else does not accidentally delete the database file. Deletion of the database file will result in the total loss of all your information (including all your passwords!) and a lot of inconvenience to manually retrieve your logins for various web applications. Do not share the credentials to access your database file with anyone unless you absolutely trust them (spouse, child, etc.). + +TIP: You can safely store your database file in the cloud (OneDrive, Dropbox, Google Drive, Nextcloud, Syncthing, etc.). The database file is always fully encrypted; unencrypted data is never written to disk and is never accessible to your cloud storage provider. We recommend using a storage service that keeps automatic backups (version history) of your database file in the event of corruption or accidental deletion. + === Opening an Existing Database To open an existing database, perform the following steps: @@ -51,9 +58,11 @@ image::unlock_database.png[] 3. Enter the password for your database. -4. _(Optional)_ Browse for the Key File if you have chosen it as an additional authentication factor while creating the database. Refer to the KeePassXC User Guide for more information on setting a Key File as an additional authentication factor. +4. _(Optional)_ Click *I have a key file (A)* if you have one as an additional authentication factor for your database. -5. Click *OK*. The database opens and the following screen is displayed: +5. _(Optional)_ Plug in your configured YubiKey or OnlyKey to use it as an additional authentication factor. If you don't see it listed, press the refresh button *(B)*. + +6. Click *OK*. The database opens and the following screen is displayed: + .Unlocked database image::database_view.png[] @@ -66,35 +75,24 @@ NOTE: On Windows, you will be prompted to authenticate to Windows Hello after un .Windows Hello example image::quick_unlock_windows_hello.png[] -When your database is locked, you will see the following unlock dialog. Simply press _Enter_ or click on _Unlock Database_ to initiate the biometric authentication process. If you are using a hardware key (e.g. Yubikey), it must be connected to your computer to complete the unlock. +When your database is locked, you will see the following unlock dialog. Simply press kbd:[Enter] or click on _Unlock Database_ to initiate the biometric authentication process. If you are using a hardware key (e.g. Yubikey), it must be connected to your computer to complete the unlock. .Quick Unlock image::quick_unlock.png[] // tag::advanced[] -=== Expired Entries -By default, KeePassXC will show entries that are expired or will be expiring within 3 days after unlocking the database. This feature allows you to change your passwords before they expire and be aware of passwords that are no longer valid. You can disable or change this feature in the Application Settings. +NOTE: By default, KeePassXC will show entries that are expired or will be expiring within 3 days after unlocking the database. This feature allows you to change your passwords before they expire and be aware of passwords that are no longer valid. You can disable or change this feature in the Application Settings. -=== Advanced Save Options -There are three ways that KeePassXC can handle database files. This behavior is set in the Application Settings under _File Operations_. - -1. _(Default)_ *Safe saves* create a temporary database file alongside the existing one and atomically move it into place when all writing is complete. This prevents database corruption in the case of application crashes, loss of power, or other interruptions. - -2. *Temporary file saves* create a database in the temporary files folder. This database is then moved into place overtop of the existing file. Although rare, interruptions in this move process could leave your database in an unknown state. This option is useful for overcoming poorly behaved cloud sync tools. - -3. *Direct-write saves* write directly to the existing database file. This is an unsafe operation since any interruption can leave your entire database inaccessible. We only recommend using this option when interfacing with Linux GVFS services (e.g. Google Cloud on Gnome) and other types of storage services that host a virtual drive system. - -In addition to these save options, KeePassXC can create a backup of your existing database file just prior to saving. This backup will be saved at the path specified in the *Backup destination* field. This path can be absolute or relative. The latter will be resolved according to the databases path. It is possible to specify a custom naming scheme with placeholders. See xref:UserGuide.adoc#_backup_path_placeholders[Backup Path Placeholders] for available placeholders and examples. - -image::save_options.png[] // end::advanced[] +=== Entry Handling +Entries in KeePassXC are the fundamental units where all your sensitive information is stored. Each entry can contain various fields such as usernames, passwords, URLs, attachments, and notes. You can create, edit, clone, and delete entries as needed. Additionally, KeePassXC supports advanced features like TOTP for two-factor authentication, custom attributes, and entry history to track changes over time. Proper management of entries ensures that your data is organized, secure, and easily accessible when needed. -=== Adding an Entry +==== Adding an Entry All the details such as usernames, passwords, URLs, attachments, notes, and so on are stored in database entries. You can create as many entries as you want in the database. To add an entry, perform the following step: -1. Navigate to Entries > New Entry (Or, press Ctrl+N). The following screen appears: +1. Navigate to Entries > New Entry (or press kbd:[Ctrl+N]). The following screen appears: + .Adding a new entry image::edit_entry.png[] @@ -112,18 +110,18 @@ image::edit_entry.png[] 5. Click *OK* to add the entry to your database. -=== Editing an Entry +==== Editing an Entry To edit the details in an entry, perform the following steps: 1. Select the entry you want to edit. -2. Press `Enter`, click the edit toolbar icon, or right-click and select Edit Entry from the menu. +2. Press kbd:[Enter], click the edit toolbar icon, or right-click and select Edit Entry from the menu. 3. Make the desired changes. 4. Click *OK*. -=== Adding TOTP to an Entry +==== Adding TOTP to an Entry Timed One-Time Passwords (TOTP) are a popular choice for two-factor authentication methods. These codes are typically six digits long and change every 30 seconds. They are derived from a shared secret value and the current time. Once set up, KeePassXC can calculate TOTP codes like any authenticator app, such as Google Authenticator. The codes can be used with copy/paste, browser extension, and Auto-Type. TIP: Your computer time must be synchronized with an internet time source to generate valid TOTP codes, https://www.nist.gov/pml/time-and-frequency-division/time-distribution/internet-time-service-its[read more here]. @@ -145,24 +143,34 @@ After an entry is configured with TOTP, you will see a clock icon in that entry' .TOTP Usage image::totp_usage_examples.png[] -=== Deleting an Entry +==== Entry Icons +You can select an icon to be displayed with each entry for easy identification. KeePassXC comes with a set of default icons that you can use or you can use your own custom icons. If you defined a URL with an entry, you can also download the favorite icon for that particular website. + +NOTE: To delete a custom icon, go to <> where you can purge unused icons and delete one or more icons at a time. + +.Entry icon selection +image::edit_entry_icons.png[] + +TIP: Each KeePass application has different default icons. If you use a mobile app or KeePass2, be aware that the default icons may not be exactly correspond to the KeePassXC icons. + +==== Deleting an Entry To delete an entry, perform the following steps: -1. Select the entry you want to delete and press the `Delete` button on your keyboard. +1. Select the entry you want to delete and press the kbd:[Del] button on your keyboard. 2. You will be prompted to move the entry to the Recycle Bin (if enabled). + NOTE: You can disable the recycle bin within the Database Settings. If the recycle bin is disabled then deleted entries will be permanently removed from the database. -3. To permanently delete the entry, navigate to the Recycle Bin, select the entry you want to delete and press the `Delete` button on your keyboard. +3. To permanently delete the entry, navigate to the Recycle Bin, select the entry you want to delete and press the kbd:[Del] button on your keyboard. // tag::advanced[] -=== Clone an Entry +==== Clone an Entry Creating a clone of an entry provides you a ready-to-use template for creating new entries with similar details of a master entry. To create a clone of an existing entry, perform the following steps: -1. Right-click on the entry for which you want to create a clone and select _Clone Entry_. Alternatively, select the desired entry and press `Ctrl+K`. +1. Right-click on the entry for which you want to create a clone and select _Clone Entry_. Alternatively, select the desired entry and press kbd:[Ctrl+K]. + .Clone entry from context menu image::clone_entry.png[] @@ -180,12 +188,73 @@ image::clone_entry_dialog.png[,50%] .References in a cloned entry image::clone_entry_references.png[] -4. You can create your own references using the xref:UserGuide.adoc#_entry_cross_reference[Entry Reference Syntax] +4. You can create your own references using the <> -== Searching the Database -KeePassXC provides an enhanced and granular search features the enables you to search for specific entries in the databases using the different modifiers, wild card characters, and logical operators. +==== Entry URL Handling +KeePassXC can handle URLs in various ways. Standard URLs will be opened in your default browser. URLs that start with schemas handled by your Operating System will launch the associated application, for example `ftp://` or `ssh://`. You can also use the following URL schemas to perform specific actions: -=== Modifiers and Fields +|=== +|Schema | Example | Description + +|cmd:// +|`cmd://ssh {USERNAME}@example.com -p 2222` +|Launches the specified command line executable with the specified arguments. The executable must be present on your PATH or an absolute path must be specified. + +|kdbx:// +|`kdbx://~/dbs/passwords.kdbx` +|Opens the specified database file. Set the entry's username to the keyfile path (if required) and password to the database password. The database will open in a new tab. + +|=== + +=== Advanced Entry Handling +KeePassXC offers several advanced options for managing your database entries. Additional Attributes allow you to store extra information required by some applications and websites. Attachments enable you to attach files to entries, stored as encrypted binaries, which can be previewed directly in the application (text and images). Icons can be selected or downloaded for easy identification of entries. The Properties section lets you view basic properties such as creation, modification, and last accessed times, and retrieve an entry's UUID for references. KeePassXC also maintains a history of changes to entries, allowing you to view, restore, or delete previous versions of an entry. + +==== Additional Attributes +A lot of applications and web sites now require providing additional information when you create accounts. The additional information is used to block hackers if any suspicious activity is detected. In addition, the additional information you provide can be used to reset passwords if you forget them. You can also store arbitrary information here that can be copied to the clipboard or Auto-Typed using the `{S:}` action code. + +To protect an attribute from being displayed by default, activate the _Protect_ checkbox *(A)*. To show the contents of the attribute while keeping it protected, press the _Reveal_ button *(B)*. + +.Additional attributes example +image::edit_entry_attributes.png[] + +==== Attachments +You can attach files to any entry in your database by pressing the _Add_ button *(A)*. These files are added to the database and stored as encrypted binaries. You can open, save, or delete attachments from this interface *(B)*. + +NOTE: When you try to open the attached file, KeePassXC extracts the attachment to a temporary file and opens it using the default application associated with the file type. After finishing viewing or editing the file, you can choose between importing or discarding the changes that you made to the temporary file. KeePassXC securely deletes the temporary file by overwriting it. + +.Attachments interface +image::edit_entry_attachments.png[] + +==== Foreground and Background Color +You can change the foreground *(A)* and/or background *(B)* color that this entry will use in the entry lists. Click the corresponding box to open the color picker dialog. + +.Color picker dialog +image::edit_entry_colors.png[] + +==== Properties +KeePassXC lets you view the basic properties such as date and time of creation, modification, and when last accessed. This is also where you can retrieve an entry's UUID for use in references. + +.Entry properties view +image::edit_entry_properties.png[] + +==== History +KeePassXC maintains a history of changes you make to your entries. Each time you change an entry, KeePassXC automatically creates a backup copy of the current, non-modified entry before saving the new values. You can view the changes you made previously, restore, and delete the history of changes you made. The age of the history item, the changes that were made, and the entry's size are shown in the table view. + + * Show: Display this history item for review, a read-only copy of the entry will be shown. + * Restore: Reinstate the selected history item as the active entry details. + * Delete: Delete the selected history item. + * Delete All: Delete the entire history for this entry. + +.Entry history view +image::edit_entry_history.png[] + +NOTE: Restoring an old history item will store the current entry settings as a new history item. + +// end::advanced[] +=== Search +KeePassXC provides a robust search that enables you to find specific entries in the databases using different modifiers, wild card characters, and logical operators. By default, search considers the following fields when matching your query: Title, Username, URL, Tags, and Notes. To include other fields and/or narrow your search to specific fields, you can use the search syntax described below. + +==== Modifiers and Fields [grid=rows, frame=none, width=70%] |=== |Modifier |Description @@ -201,14 +270,15 @@ The following fields can be searched along with their abbreviated name in parent * Title (t) * Username (u) * Password (p, pw) -* URL +* URL (url) * Notes (n) * Attribute names and values (attr) * Attachment (attach) * Group (g) +* Tags (tag) * Entry State (is:expired, is:weak) -=== Wild Card Characters and Logical Operators +==== Wild Card Characters and Logical Operators [grid=rows, frame=none, width=70%] |=== |Wild Card Character |Description @@ -218,7 +288,7 @@ The following fields can be searched along with their abbreviated name in parent |\| |Logical OR |=== -=== Sample Search Queries +==== Sample Search Queries The following tables lists a few samples search queries for your reference: |=== @@ -236,63 +306,39 @@ The following tables lists a few samples search queries for your reference: |`+attr:mystring123` |Searches all additional attributes for any name OR value equal to mystring123. +|`+tag:personal` +| Search exactly for the 'personal' tag and do not include tags such as 'my personal'. + |`is:expired is:weak` |Searches for all expired entries with weak passwords. |=== -== Advanced Entry Options -=== Additional Attributes -A lot of applications and web sites now require providing additional information when you create accounts. The additional information is used to block hackers if any suspicious activity is detected. In addition, the additional information you provide can be used to reset passwords if you forget them. You can also store arbitrary information here that can be copied to the clipboard or Auto-Typed using the `{S:}` action code. +// tag::advanced[] +=== Merging Databases +KeePassXC allows you to merge entries from one database into another through the _Database_ -> _Merge From Database_ menu item. When merging, entries from the specified database will be imported into your currently open database. The merge process compares entries based on their unique identifiers (UUIDs) and modified timestamp. When an entry UUID matches, no matter which group it is in, the most recently modified version will be made the current and the previous version will be placed into the entry's history. Any new entries and/or groups will be added to the open database. This feature is useful for consolidating multiple databases or synchronizing databases from conflict files in a cloud storage system. -To protect an attribute from being displayed by default, activate the _Protect_ checkbox *(A)*. To show the contents of the attribute while keeping it protected, press the _Reveal_ button *(B)*. +NOTE: When you delete entries, a record of that deletion (the entry UUID) is stored to prevent that entry from reappearing from a merge operation. An existing entry that has the same UUID as a deleted item will be removed from the database without prompt. -.Additional attributes example -image::edit_entry_attributes.png[] +=== Advanced Save Options +There are three ways that KeePassXC can handle database files. This behavior is set in the Application Settings under _File Operations_. -=== Attachments -You can attach files to any entry in your database by pressing the _Add_ button *(A)*. These files are added to the database and stored as encrypted binaries. You can open, save, or delete attachments from this interface *(B)*. +1. _(Default)_ *Safe saves* create a temporary database file alongside the existing one and atomically move it into place when all writing is complete. This prevents database corruption in the case of application crashes, loss of power, or other interruptions. -NOTE: When you try to open the attached file, KeePassXC extracts the attachment to a temporary file and opens it using the default application associated with the file type. After finishing viewing or editing the file, you can choose between importing or discarding the changes that you made to the temporary file. KeePassXC securely deletes the temporary file by overwriting it. +2. *Temporary file saves* create a database in the temporary files folder. This database is then moved into place overtop of the existing file. Although rare, interruptions in this move process could leave your database in an unknown state. This option is useful for overcoming poorly behaved cloud sync tools. -.Attachments interface -image::edit_entry_attachments.png[] +3. *Direct-write saves* write directly to the existing database file. This is an unsafe operation since any interruption can leave your entire database inaccessible. We only recommend using this option when interfacing with Linux GVFS services (e.g. Google Cloud on Gnome) and other types of storage services that host a virtual drive system. -=== Foreground and Background Color -You can change the foreground *(A)* and/or background *(B)* color that this entry will use in the entry lists. Click the corresponding box to open the color picker dialog. +=== Database Backup Options +In addition to these save options, KeePassXC can create a backup of your existing database file just prior to saving. This backup will be saved at the path specified in the *Backup destination* field. This path can be absolute or relative. The latter will be resolved according to the databases path. It is possible to specify a custom naming scheme with placeholders. See <> for available placeholders and examples. -.Color picker dialog -image::edit_entry_colors.png[] +image::save_options.png[] -=== Icons -You can select an icon to be displayed with each entry for easy identification. KeePassXC comes with a set of default icons that you can use or you can use your own custom icons. If you defined a URL with an entry, you can also download the favorite icon for that particular website. +Alternatively, backups can be created on-demand using the _Database_ -> _Save Database Backup..._ menu feature. -NOTE: To delete a custom icon, go to xref:UserGuide.adoc#_database_maintenance[Database Maintenance] where you can purge unused icons and delete one or more icons at a time. +.Saving a database backup +image::save_database_backup.png[,40%] -.Entry icon selection -image::edit_entry_icons.png[] - -TIP: Each KeePass application has different default icons. If you use a mobile app or KeePass2, be aware that the default icons may not be exactly correspond to the KeePassXC icons. - -=== Properties -KeePassXC lets you view the basic properties such as date and time of creation, modification, and when last accessed. This is also where you can retrieve an entry's UUID for use in references. - -.Entry properties view -image::edit_entry_properties.png[] - -=== History -KeePassXC maintains a history of changes you make to your entries. Each time you change an entry, KeePassXC automatically creates a backup copy of the current, non-modified entry before saving the new values. You can view the changes you made previously, restore, and delete the history of changes you made. The age of the history item, the changes that were made, and the entry's size are shown in the table view. - - * Show: Display this history item for review, a read-only copy of the entry will be shown. - * Restore: Reinstate the selected history item as the active entry details. - * Delete: Delete the selected history item. - * Delete All: Delete the entire history for this entry. - -.Entry history view -image::edit_entry_history.png[] - -NOTE: Restoring an old history item will store the current entry settings as a new history item. - -== Automatic Database Opening +=== Automatic Database Opening You can setup one or more databases to open automatically when you unlock a single database. This is done by *(1)* defining a special group named `AutoOpen` with *(2)* entries that contain the file path and credentials for each database that should be opened. There is no limit to the number of databases that can be opened. TIP: Case matters with auto open, the group name must be exactly `AutoOpen` and it must be a child of the root group. @@ -329,6 +375,7 @@ image::database_settings.png[] * *Database name:* This is the default identifier for your database and is shown in the tab bar and title bar (when active). You can change this name as desired. * *Database description:* Provide some meaningful description for your database. * *Default username:* Provide a default username for all new entries that you create in this database. + * *Public Databse Metadata:* Here you can set a public (unencrypted) name, icon, and color for your database. This is used on the database unlock screen to help distinguish multiple databases from each other. * *Max history items:* This is the maximum number of history items that are stored for each entry. When you set this to 0, no history will be saved. Set this value to a low value to prevent the database from getting too large (we recommend no more than 10). * *Max. history size:* When the history of an entry gets above this size, it is truncated. For example, this happens when entries have large attachments. Set this value small to prevent the database from getting too large (we recommend 6 MiB). * *Use recycle bin:* Select this check-box if you want deleted entries to move to the recycle bin instead of being permanently removed. The recycle bin will be created if it does not already exist after your first deletion. To delete entries permanently, you must empty the recycle bin manually. @@ -365,42 +412,27 @@ The following key derivation functions are supported: * Argon2 (KDBX 4 – recommended): KDBX 4, the Argon2 key derivation function can be used for transforming the composite master key (as protection against dictionary attacks). The main advantage of Argon2 over AES-KDF is that it provides a better resistance against GPU/ASIC attacks (due to being a memory-hard function). The number of iterations scales linearly with the required time. By increasing the memory parameter, GPU/ASIC attacks become harder and the required time increases. The parallelism parameter can be used to specify how many threads should be used. We recommend using Argon2id to prevent against timing-based attacks. Argon2d offers maximum compatibility with other KeePass-based apps, the default settings provide sufficient protection against any known attacks. -== Database Maintenance +=== Database Maintenance KeePassXC offers some maintenance features that can be applied to clean up your database. Navigate to _Database_ -> _Database settings_ then click on _Maintenance_ on the left hand panel. The following screen appears. On this screen you can delete multiple icons at once and purge any unused icons in your database. image::database_maintenance.png[] -=== Creating a YubiKey backup -It is advisable to have a backup replica YubiKey In case your main YubiKey gets damaged, lost, or stolen. The same HMAC key will need to be written to both keys. To do this you can either use the YubiKey Personalization Tool GUI or the ykpersonalize CLI tool. The steps for the CLI tool are shown: +== Remote database support +KeePassXC provides support for syncing database files that reside in a remote location. If you can download/upload the database file via a commandline tool (e.g. rsync, ssh, scp etc.) KeePassXC offers easy to use functionality to sync the remote database. -1. Create a 20 byte HMAC key: -+ -``` -dd status=none if=/dev/random bs=20 count=1 | xxd -p -c 40 -``` +=== Sync with remote database +Open the remote sync settings via _Database > Database Settings… > Remote_ to create commands to sync a local database or a temporary local copy of a remote database. -2. Write the HMAC key to slot 2 _(Set through the first switch. Out of the box the YubiKey OTP resides in slot 1)_: -+ -``` -ykpersonalize -2 -a -ochal-resp -ochal-hmac -ohmac-lt64 -oserial-api-visible -oallow-update -``` +Define a name for your sync command and specify a download *(A)* as well as an upload command *(B)*. The command and/or input need a `{TEMP_DATABASE}` placeholder specified where the remote database is temporarily stored. Do not forget to save the command settings with the save button *\(C)*. Remote settings are added as menu entries below the _Remote Sync…_ menu for quick access. -You will be asked to enter the HMAC key you created earlier, copy/paste they key output in the first step. Repeat step 2 for your second YubiKey using the same HMAC key from before. We recommend storing your HMAC key in a safe place (e.g., printed on paper) in case you need to recreate another key. +WARNING: If your download or upload command require a password prompt, the command will most likely not succeed. In case of an SSH connection (e.g. sftp), it is recommended to use <> so that no password prompt is needed. + +.Remote sync settings +image::sync_remote_settings.png[] + +Select the remote sync command from the _Database > Remote Sync…_ menu to start the syncing process and a progress bar will show up in the lower right corner. + +WARNING: In case the remote database is changed by another user/process after the downloading command finishes and before uploading again, those changes will be overwritten. Syncing is not an atomic operation. -== Command Line Tool -KeePassXC comes with the command line tool *keepassxc-cli* to access, view, and manipulate your database directly from a terminal window. The tool is documented through a separate man page, which can be shown using `man keepassxc-cli`, or through the on-demand help using `keepassxc-cli [command] -h`. An online version of the man page is https://github.com/keepassxreboot/keepassxc/blob/master/docs/man/keepassxc-cli.1.adoc[available on GitHub]. // end::advanced[] - -== Storing a Database File -The database file that you create might contain highly sensitive data and must be stored in a very secure way. You must make sure that the database is always protected with a strong and long password. The database file that is protected with a strong and long password is secure and encrypted while stored on your computer or cloud storage service. - -Make sure that you or someone else does not accidentally delete the database file. Deletion of the database file will result in the total loss of all your information (including all your passwords!) and a lot of inconvenience to manually retrieve your logins for various web applications. Do not share the credentials to access your database file with anyone unless you absolutely trust them (spouse, child, etc.). - -TIP: You can safely store your database file in the cloud (OneDrive, Dropbox, Google Drive, Nextcloud, Syncthing, etc.). The database file is always fully encrypted; unencrypted data is never written to disk and is never accessible to your cloud storage provider. We recommend using a storage service that keeps automatic backups (version history) of your database file in the event of corruption or accidental deletion. - -== Backing up a Database File -It is a good practice to create copies of your database file and store the copies of your database on a different computer, smart phone, or cloud storage space such a Google Drive or Microsoft OneDrive. Backups can be created automatically by selecting the _Backup database file before saving_ option in the application settings. Additionally, you can create a backup on-demand using the _Database_ -> _Save Database Backup..._ menu feature. - -.Saving a database backup -image::save_database_backup.png[,40%] // end::content[] diff --git a/docs/topics/DownloadInstall.adoc b/docs/topics/DownloadInstall.adoc index f5a967ec5..ed24e3c79 100644 --- a/docs/topics/DownloadInstall.adoc +++ b/docs/topics/DownloadInstall.adoc @@ -38,7 +38,7 @@ To install KeePassXC on Microsoft Windows, perform the following steps: .Install wizard image::install_wizard_1.png[,80%] -2. Click Next and follow the simple instructions on the KeepPassXC Setup Wizard to complete the installation. You will have the option to choose your install location, add a desktop shortcut, and launch on startup. +2. Click Next and follow the simple instructions on the KeePassXC Setup Wizard to complete the installation. You will have the option to choose your install location, add a desktop shortcut, and launch on startup. + .Install wizard (cont) image::install_wizard_2.png[,80%] @@ -59,7 +59,7 @@ image::linux_store.png[] The Snap and Flatpak options are sandboxed applications (more secure). The Native option is installed with the operating system files. Read more about the limitations of these options here: https://keepassxc.org/docs/#faq-appsnap-yubikey[KeePassXC Snap FAQ] -NOTE: KeePassXC stores a configuration file in `~/.cache` to remember window position, recent files, and other local settings. If you mount this folder to a tmpdisk you will lose settings after reboot. +NOTE: KeePassXC stores a configuration file in `~/.local/state` to remember window position, recent files, and other local settings. If you mount this folder to a tmpdisk you will lose settings after reboot. === macOS To install the KeePassXC app on macOS, double click on the downloaded DMG file and use the click and drag option as shown: diff --git a/docs/topics/ImportExport.adoc b/docs/topics/ImportExport.adoc index bcae4ce57..4dcce0a25 100644 --- a/docs/topics/ImportExport.adoc +++ b/docs/topics/ImportExport.adoc @@ -3,14 +3,16 @@ include::.sharedheader[] :imagesdir: ../images // tag::content[] -== Importing External Databases +== Importing Databases KeePassXC allows you to import external databases from the following options: * Comma Separated Values (.csv) * 1Password Export (.1pux) * 1Password Vault (.opvault) * Bitwarden (.json) +* Proton Pass (.json) * KeePass 1 Database (.kdb) +* Remote database (.kdbx) To import any of these files, start KeePassXC and either click the `Import File` button on the welcome screen or use the menu Database > Import... to launch the Import Wizard. @@ -31,14 +33,17 @@ image::csv_import.png[] 3. Click `Done` to complete the import. If you chose to create a new database, the New Database dialog will appear. Otherwise your entries will be nested under the group you chose for the existing database. -=== Importing 1Password Export +=== Importing from Other Applications +KeePassXC allows you to import databases from various applications including 1Password (1PUX and OPVault), Bitwarden, and Proton Pass. Each import option involves selecting the file, providing necessary credentials (if required), and choosing to import into a new or existing database. Note that CSV, 1Password Export, Bitwarden, and Proton Pass files are unencrypted and should be securely deleted after import. + +==== 1Password Export WARNING: A 1Password Export file is unencrypted and you should securely delete this file after successfully importing it into KeePassXC. 1. Open the Import Wizard as shown above. Select the 1Password Export option. 2. Click `Continue` to unlock and preview the import. Click `Done` to complete the import. -=== Importing 1Password OPVault +==== 1Password OPVault NOTE: You must have 1Password version 7 or 8 to export your data to an OPVault. If you are using a newer version of 1Password, you should use the 1Password Export (1PUX) format instead. Save your 1Password Vault locally to create an OPVault directory. Please see 1Password instructions on how to do this. Once an OPVault is created, perform the following steps: @@ -47,7 +52,7 @@ Save your 1Password Vault locally to create an OPVault directory. Please see 1Pa 2. Enter the password for your vault and click `Continue` to unlock and preview the import. Click `Done` to complete the import. -=== Importing Bitwarden +==== Bitwarden WARNING: A Bitwarden Export file may be unencrypted and you should securely delete this file after successfully importing it into KeePassXC. 1. Open the Import Wizard as shown above. Select the Bitwarden option. @@ -56,6 +61,13 @@ WARNING: A Bitwarden Export file may be unencrypted and you should securely dele 3. Click `Continue` to unlock and preview the import. Click `Done` to complete the import. +==== Proton Pass +WARNING: A Proton Pass Export file is unencrypted and you should securely delete this file after successfully importing it into KeePassXC. + +1. Open the Import Wizard as shown above. Select the Proton Pass option. + +2. Click `Continue` to preview the import. Click `Done` to complete the import. + === Importing KeePass 1 Database KeePass 1 database is an older format of the database created using a legacy version of KeePass. KeePassXC lets your import this older format of the database and you can seamlessly start using this database in your new KeePassXC application. @@ -67,9 +79,26 @@ To import a KeePass 1 database file in KeePassXC, perform the following steps: 3. Click `Continue` to unlock and preview the import. Click `Done` to complete the import. +=== Importing Remote Database +Database files that are stored in a remote location can be imported or opened with KeePassXC if you provide a command to download the file from the remote location. + +To import (or temporarily open) a remote database file in KeePassXC, perform the following steps: + +1. Open the Import Wizard as shown above. Select the Remote Database option. + +2. Enter a command to download the remote database. If necessary, enter input that needs to be passed to the command. The command and/or input need a `{TEMP_DATABASE}` placeholder specified where the remote database is temporarily stored. + +3. Enter the password for your database and optionally provide a key file. + +4. Click `Continue` to unlock and preview the import. Click `Done` to complete the import. + +Opening without importing a remote database is possible by selecting Temporary Database in the Import Into section of the wizard. + == Exporting Databases KeePassXC supports multiple ways to export your database for transfer to another program or to print out and archive. +WARNING: These exports do not contain all the information in your database due to various limitations in the export format. For example, the CSV export does not support attachments, advanced attributes, Auto-Type settings, or custom icons. The XML export does not support attachments. The HTML export is mainly for printing and does not support attachments and some custom data fields. + WARNING: Exporting your database will result in all of your passwords and sensitive information being stored in an unencrypted format. We do not recommend saving your exported database for long periods of time as that can cause a compromise of sensitive information. .Database export menu diff --git a/docs/topics/KeeShare.adoc b/docs/topics/KeeShare.adoc index 75769bdb4..882e7f017 100644 --- a/docs/topics/KeeShare.adoc +++ b/docs/topics/KeeShare.adoc @@ -16,7 +16,7 @@ To use sharing, you need to enable it for the application. .KeeShare Application Settings image::keeshare_application_settings.png[] -=== Sharing Credentials +=== Setup a Shared Group If you checked _Allow export_ in the Sharing settings you can now share a group of passwords. Sharing is always defined on a particular group. If you enable sharing on a group, every entry under this group, and its children, are shared. If you enable sharing on the root node, **every password** inside your database gets shared! NOTE: KeeShare does not synchronize group structure after the initial share is created. At this time, KeeShare operates at the entry level; shared entries moved outside of a shared group are still synchronized. diff --git a/docs/topics/KeyboardShortcuts.adoc b/docs/topics/KeyboardShortcuts.adoc index 034633659..b968b9813 100644 --- a/docs/topics/KeyboardShortcuts.adoc +++ b/docs/topics/KeyboardShortcuts.adoc @@ -3,51 +3,62 @@ include::.sharedheader[] :imagesdir: ../images // tag::content[] -NOTE: On macOS please substitute `Ctrl` with `Cmd` (aka `⌘`). +NOTE: On macOS please substitute kbd:[Ctrl] with kbd:[Cmd] (AKA kbd:[⌘]). [grid=rows, frame=none, width=75%] |=== -|Action | Keyboard Shortcut +|Action | Keyboard Shortcut -|Settings | Ctrl + , -|Open Database | Ctrl + O -|Save Database | Ctrl + S -|Save Database As | Ctrl + Shift + S -|New Database | Ctrl + Shift + N -|Close Database | Ctrl + W ; Ctrl + F4 -|Lock All Databases | Ctrl + L -|Database Settings | Ctrl + Shift + , -|Database Reports | Ctrl + Shift + R -|Quit | Ctrl + Q -|New Entry | Ctrl + N -|Edit Entry | Enter ; Ctrl + E -|Delete Entry | Delete -|Clone Entry | Ctrl + K -|Copy Username | Ctrl + B -|Copy Password | Ctrl + C -|Copy URL | Ctrl + U -|Open URL | Ctrl + Shift + U -|Copy TOTP | Ctrl + T -|Copy Password and TOTP | Ctrl + Y -|Show TOTP | Ctrl + Shift + T -|Trigger AutoType | Ctrl + Shift + V -|Add key to SSH Agent | Ctrl + H -|Remove key from SSH Agent | Ctrl + Shift + H -|Move entry up (if unsorted) | Ctrl + Alt + Up -|Move entry down (if unsorted) | Ctrl + Alt + Down -|Sort Groups A-Z | Ctrl + Down -|Sort Groups Z-A | Ctrl + Up -|Minimize Window | Ctrl + M -|Hide Window | Ctrl + Shift + M -|Select Next Database Tab | Ctrl + Tab ; Ctrl + PageDn -|Select Previous Database Tab | Ctrl + Shift + Tab ; Ctrl + PageUp -|Select the nth database | Ctrl + n, where n is the number of the database tab -|Toggle Passwords Hidden | Ctrl + Shift + C -|Toggle Usernames Hidden | Ctrl + Shift + B -|Focus Groups (edit if focused) | F1 -|Focus Entries (edit if focused) | F2 -|Focus Search | F3 ; Ctrl + F -|Clear Search | Escape -|Show Keyboard Shortcuts | Ctrl + / +|Settings | kbd:[Ctrl + ,] +|Open Database | kbd:[Ctrl + O] +|Save Database | kbd:[Ctrl + S] +|Save Database As | kbd:[Ctrl + Shift + S] +|New Database | kbd:[Ctrl + Shift + N] +|Close Database | kbd:[Ctrl + W] + +_or_ + +kbd:[Ctrl + F4] +|Lock Current Database | kbd:[Ctrl + L] +|Lock All Databases | kbd:[Ctrl + Shift + L] +|Database Settings | kbd:[Ctrl + Shift + ,] +|Database Reports | kbd:[Ctrl + Shift + R] +|Quit | kbd:[Ctrl + Q] +|New Entry | kbd:[Ctrl + N] +|Edit Entry | kbd:[Enter] + +_or_ + +kbd:[Ctrl + E] +|Delete Entry | kbd:[Del] +|Clone Entry | kbd:[Ctrl + D] +|Copy Username | kbd:[Ctrl + B] +|Copy Password | kbd:[Ctrl + C] +|Copy URL | kbd:[Ctrl + U] +|Open URL | kbd:[Ctrl + Shift + U] +|Copy TOTP | kbd:[Ctrl + T] +|Copy Password and TOTP | kbd:[Ctrl + Y] +|Show TOTP | kbd:[Ctrl + Shift + T] +|Trigger AutoType | kbd:[Ctrl + Shift + V] +|Add key to SSH Agent | kbd:[Ctrl + H] +|Remove key from SSH Agent | kbd:[Ctrl + Shift + H] +|Move entry up (if unsorted) | kbd:[Ctrl + Alt + Up] +|Move entry down (if unsorted) | kbd:[Ctrl + Alt + Down] +|Sort Groups A-Z | kbd:[Ctrl + Down] +|Sort Groups Z-A | kbd:[Ctrl + Up] +|Minimize Window | kbd:[Ctrl + M] +|Hide Window | kbd:[Ctrl + Shift + M] +|Select Next Database Tab | kbd:[Ctrl + Tab] + +_or_ + +kbd:[Ctrl + PgDn] +|Select Previous Database Tab | kbd:[Ctrl + Shift + Tab] + +_or_ + +kbd:[Ctrl + PgUp] +|Select the nth database | kbd:[Ctrl + <n>], where kbd:[<n>] is the number of the database tab +|Toggle Passwords Hidden | kbd:[Ctrl + Shift + C] +|Toggle Usernames Hidden | kbd:[Ctrl + Shift + B] +|Focus Groups (edit if focused) | kbd:[F1] +|Focus Entries (edit if focused) | kbd:[F2] +|Focus Search | kbd:[F3] + +_or_ + +kbd:[Ctrl + F] +|Clear Search | kbd:[Esc] +|Show Keyboard Shortcuts | kbd:[Ctrl + /] |=== // end::content[] diff --git a/docs/topics/Passkeys.adoc b/docs/topics/Passkeys.adoc index b341eb3fe..bfb472024 100644 --- a/docs/topics/Passkeys.adoc +++ b/docs/topics/Passkeys.adoc @@ -5,56 +5,56 @@ include::.sharedheader[] // tag::content[] == Passkeys -Passkeys are a secure way for replacing passwords that is supported by all major browser vendors and an increasing number of websites. For more information on what Passkeys are and how they work, please go to the FIDO Alliance's documentation: https://fidoalliance.org/passkeys/ +Passkeys are a secure way for replacing passwords that is supported by all major browser vendors and an increasing number of websites. For more information on what passkeys are and how they work, please go to the FIDO Alliance's documentation: https://fidoalliance.org/passkeys/ -=== Enabling Passkey Support +=== Browser Passkey Support -KeePassXC supports Passkeys directly through the Browser Integration service. Passkeys are only supported with the use of the KeePassXC Browser Extension and a properly connected database. To enable Passkey support on the extension, you must check the _Enable Passkeys_ option in the extension settings page. +KeePassXC supports passkeys directly through the Browser Integration service. Passkeys are only supported with the use of the KeePassXC Browser Extension and a properly connected database. To enable passkey support on the extension, you must check the _Enable Passkeys_ option in the extension settings page. .Enable Passkey Support in the KeePassXC Browser Extension image::passkeys_enable_from_extension.png[,75%] -Optionally, you can disable falling back to the built-in Passkey support from your browser and operating system. If left enabled, the extension will show the default Passkey dialogs if KeePassXC cannot handle the request or the request is canceled. +Optionally, you can disable falling back to the built-in passkey support from your browser and operating system. If left enabled, the extension will show the default passkey dialogs if KeePassXC cannot handle the request or the request is canceled. === Create a New Passkey -Creating a new Passkey and authenticating with it is a simple process. This workflow will be demonstrated using GitHub as an example site. Please note that GitHub allows two use cases for Passkeys, one for 2FA only and the other for replacement of username and password entirely. We will be configuring the latter use case in this example. +Creating a new passkey and authenticating with it is a simple process. This workflow will be demonstrated using GitHub as an example site. Please note that GitHub allows two use cases for passkeys, one for 2FA only and the other for replacement of username and password entirely. We will be configuring the latter use case in this example. -After navigating to GitHub's _Settings_ -> _Password and authentication_, there is a separate section shown for Passkeys. +After navigating to GitHub's _Settings_ -> _Password and authentication_, there is a separate section shown for passkeys. .GitHub's Passkey Registration image::passkeys_github_1.png[] -After clicking the _Add a Passkey_ button, the user is redirected to another page showing the actual configuration option. +After clicking the _Add a passkey_ button, the user is redirected to another page showing the actual configuration option. .Configure Passwordless Authentication image::passkeys_github_2.png[,50%] -Clicking the _Add Passkey_ button now shows the following popup dialog for the user, asking confirmation for creating a new Passkey. +Clicking the _Add passkey_ button now shows the following popup dialog for the user, asking confirmation for creating a new passkey. .Passkey Registration Confirmation Dialog image::passkeys_register_dialog.png[,30%] -After the Passkey has been registered, a new entry is created to the database under _KeePassXC-Browser Passwords_ with _(Passkey)_ added to the entry title. The entry holds additional attributes that are used for authenticating the Passkey. +After the passkey has been registered, a new entry is created to the database under _KeePassXC-Browser Passwords_ with _(passkey)_ added to the entry title. The entry holds additional attributes that are used for authenticating the passkey. -After registration, GitHub will ask a name for the Passkey. This is only relevant for the server. +After registration, GitHub will ask a name for the passkey. This is only relevant for the server. .GitHub's Passkey Nickname image::passkeys_github_3.png[,50%] -Now the Passkey should be shown on the GitHub's Passkey section. +Now the passkey should be shown on the GitHub's passkey section. .Registered Passkeys on GitHub image::passkeys_github_4.png[] === Login With a Passkey -The Passkey created in the previous section can now be used to login to GitHub. Instead of logging in with normal credentials, choose _Sign in with a passkey_ at the bottom of GitHub's login page. +The passkey created in the previous section can now be used to login to GitHub. Instead of logging in with normal credentials, choose _Sign in with a passkey_ at the bottom of GitHub's login page. .GitHub's login page with a Passkey option image::passkeys_github_5.png[,50%] -After clicking the button, KeePassXC-Browser detects the Passkeys authentication and KeePassXC shows the following dialog for confirmation. +After clicking the button, KeePassXC-Browser detects the passkeys authentication and KeePassXC shows the following dialog for confirmation. .Passkey authentication confirmation dialog image::passkeys_authentication_dialog.png[,50%] @@ -66,36 +66,36 @@ After confirmation user is now authenticated and logged into GitHub. ==== Multiple Passkeys for a Site -Multiple Passkeys can be created for a single site. When registering a new Passkey with a different username, KeePassXC shows an option to register a new Passkey or update the previous one. Updating a Passkey will override the existing entry, so this option should be only used when actually needed. +Multiple passkeys can be created for a single site. When registering a new passkey with a different username, KeePassXC shows an option to register a new passkey or update the previous one. Updating a passkey will override the existing entry, so this option should be only used when actually needed. .Passkey authentication confirmation dialog image::passkeys_update_dialog.png[,50%] ==== Exporting Passkeys -All Passkeys in a database can be viewed and accessed from the _Database_ -> _Passkeys..._ menu item. The page shows both _Import_ and _Export_ buttons for Passkeys. +All passkeys in a database can be viewed and accessed from the _Database_ -> _Passkeys..._ menu item. The page shows both _Import_ and _Export_ buttons for passkeys. .Passkeys Overview image::passkeys_all_passkeys.png[] -After selecting one or more entries, the following dialog is shown. One or multiple Passkeys can be selected for export from the previously selected list of entries. +After selecting one or more entries, the following dialog is shown. One or multiple passkeys can be selected for export from the previously selected list of entries. .Passkeys Export Dialog image::passkeys_export_dialog.png[,65%] -Exported Passkeys are stored in JSON format using the `.passkey` file extension. The file includes all relevant information for importing a Passkey to another database or saving a backup. +Exported passkeys are stored in JSON format using the `.passkey` file extension. The file includes all relevant information for importing a passkey to another database or saving a backup. -WARNING: The exported Passkey file is unencrypted and should be securely stored. +WARNING: The exported passkey file is unencrypted and should be securely stored. ==== Importing Passkeys -An exported Passkey can be imported directly to a database or to an entry. To import directly, use the _Database_ -> _Import Passkey_ menu item. -When right-clicking an entry, a separate menu item for _Import Passkey_ is shown. This is useful if user wants to import a previously created Passkey to an existing entry. +An exported passkey can be imported directly to a database or to an entry. To import directly, use the _Database_ -> _Import Passkey_ menu item. +When right-clicking an entry, a separate menu item for _Import Passkey_ is shown. This is useful if user wants to import a previously created passkey to an existing entry. .Import Passkey to an Entry image::passkeys_import_passkey_to_entry.png[,50%] -After selecting a Passkey file to import, a separate dialog is shown where you can select which database, group, and entry to target. By default, the group is set to _Imported Passkeys_. The default action is to create a new entry that contains the imported Passkey. +After selecting a passkey file to import, a separate dialog is shown where you can select which database, group, and entry to target. By default, the group is set to _Imported Passkeys_. The default action is to create a new entry that contains the imported passkey. .Passkey import dialog image::passkeys_import_dialog.png[,65%] diff --git a/docs/topics/PasswordGenerator.adoc b/docs/topics/PasswordGenerator.adoc index a1f1915e9..b36b2ed9a 100644 --- a/docs/topics/PasswordGenerator.adoc +++ b/docs/topics/PasswordGenerator.adoc @@ -19,9 +19,8 @@ image::password_generator.png[] 3. Select the length of the desired password by dragging the Length slider. 4. Select the character-sets that you want to include in your password. -5. Use the regenerate button (Ctrl + R) to make a new password using the chosen options. -6. Use the clipboard button (Ctrl + C) to copy the generated password to the clipboard. -// tag::advanced[] +5. Use the regenerate button (kbd:[Ctrl + R]) to make a new password using the chosen options. +6. Use the clipboard button (kbd:[Ctrl + C]) to copy the generated password to the clipboard. 7. Click the Advanced button to specify additional conditions for your desired password. + .Advanced Password Generator Options @@ -40,7 +39,6 @@ Word Count slider. 3. In the Word Separator field, enter a character, word, number, or space that you want to use as a separator between the words in your passphrase. 4. _(Optional)_ You can choose a word case between lower, upper, and title case options. 5. _(Optional)_ You can also load your own custom word lists. Click the plus sign button to the right of the wordlist selection dialog to choose a custom word list. You can download alternative lists from the https://www.eff.org/deeplinks/2016/07/new-wordlists-random-passphrases[EFF's Website] or from https://github.com/redacted/XKCD-password-generator#additional-languages[GitHub]. -6. Click the Regenerate button (Ctrl + R) to generate a new random passphrase. -7. Click the Clipboard button (Ctrl + C) to copy the passphrase to the clipboard. -// end::advanced[] +6. Click the Regenerate button (kbd:[Ctrl + R]) to generate a new random passphrase. +7. Click the Clipboard button (kbd:[Ctrl + C]) to copy the passphrase to the clipboard. // end::content[] diff --git a/docs/topics/Reference.adoc b/docs/topics/Reference.adoc index 4171ed9a5..b677efb6b 100644 --- a/docs/topics/Reference.adoc +++ b/docs/topics/Reference.adoc @@ -18,6 +18,8 @@ This section contains full details on advanced features available in KeePassXC. |{NOTES} |Notes |{TOTP} |Current TOTP value (if configured) |{S:<ATTRIBUTE_NAME>} |Value for the given attribute (case sensitive) +|{T-CONV:/<PLACEHOLDER>/<METHOD>/} |Text conversion for resolved placeholder (eg, {USERNAME}) using the following methods: UPPER, LOWER, BASE64, HEX, URI, URI-DEC +|{T-REPLACE-RX:/<PLACEHOLDER>/<REGEX>/<REPLACE>/} |Use a regular expression to find and replace data from a resolved placeholder (eg, {USERNAME}). Refer to match groups using $1, $2, etc. |{URL:RMVSCM} |URL without scheme (e.g., https) |{URL:WITHOUTSCHEME} |URL without scheme |{URL:SCM} |URL Scheme @@ -75,8 +77,8 @@ Examples: + |Press the corresponding keyboard key |{UP}, {DOWN}, {LEFT}, {RIGHT} |Press the corresponding arrow key -|{F1}, {F2}, ..., {F16} |Press F1, F2, etc. -|{LEFTBRACE}, {RIGHTBRACE} |Press `{` or `}`, respectively +|{F1}, {F2}, ..., {F16} |Press kbd:[F1], kbd:[F2], etc. +|{LEFTBRACE}, {RIGHTBRACE} |Press kbd:[{] or kbd:[}], respectively |{<KEY> X} |Repeat <KEY> X times (e.g., {SPACE 5} inserts five spaces) |{DELAY=X} |Set delay between key presses to X milliseconds |{DELAY X} |Pause typing for X milliseconds @@ -88,10 +90,10 @@ Examples: + |=== |Modifier |Description -|+ |SHIFT -|^ |CTRL -|% |ALT -|# |WIN/CMD +|+ |kbd:[Shift] +|^ |kbd:[Ctrl] +|% |kbd:[Alt] +|# |kbd:[Win]/kbd:[Cmd] |=== *Text Conversions:* @@ -124,5 +126,21 @@ Use regular expressions to find and replace data from a resolved placeholder. Re `C:\Backups\MyDatabase\01-05-2022.kdbx` |=== +=== Creating a YubiKey backup +It is advisable to have a backup replica YubiKey In case your main YubiKey gets damaged, lost, or stolen. The same HMAC key will need to be written to both keys. To do this you can either use the YubiKey Personalization Tool GUI or the ykpersonalize CLI tool. The steps for the CLI tool are shown: + +1. Create a 20 byte HMAC key: ++ +``` +dd status=none if=/dev/random bs=20 count=1 | xxd -p -c 40 +``` + +2. Write the HMAC key to slot 2 _(Set through the first switch. Out of the box the YubiKey OTP resides in slot 1)_: ++ +``` +ykpersonalize -2 -a -ochal-resp -ochal-hmac -ohmac-lt64 -oserial-api-visible -oallow-update +``` + +You will be asked to enter the HMAC key you created earlier, copy/paste they key output in the first step. Repeat step 2 for your second YubiKey using the same HMAC key from before. We recommend storing your HMAC key in a safe place (e.g., printed on paper) in case you need to recreate another key. // end::content[] diff --git a/docs/topics/SSHAgent.adoc b/docs/topics/SSHAgent.adoc index 5539e0e67..8b385c64c 100644 --- a/docs/topics/SSHAgent.adoc +++ b/docs/topics/SSHAgent.adoc @@ -3,12 +3,12 @@ include::.sharedheader[] :imagesdir: ../images // tag::content[] -== SSH Agent integration +== SSH Agent Integration SSH (Secure Shell) is a widely used remote secure shell protocol and is considered an industry standard for secure remote access to UNIX-like systems including Linux, BSDs, macOS and more recently even Windows received native support. SSH supports multiple types of authentication and the most widely used ones are either interactive keyboard input with a password or a public-key cryptography pair of keys. KeePassXC SSH Agent integration is built to manage SSH keys in a secure manner by either storing them completely within your KeePassXC database or by having only the decryption key of a key file that is stored elsewhere. SSH Agent integration _does not_ provide an agent itself but works as a client for any agent implementation that is OpenSSH compatible. -=== OpenSSH agent on Linux +=== OpenSSH Agent on Linux If you are using a modern desktop Linux distribution it is very likely the OpenSSH agent is already configured and running when you have logged in to a graphical desktop session. This should be true for distributions like Debian, Ubuntu (including Kubuntu, Xubuntu and Lubuntu), Linux Mint, Fedora, ElementaryOS and Manjaro. @@ -32,10 +32,10 @@ WARNING: _GNOME Keyring_ prior to release 3.27.92 had its own custom implementat It does not support any constraints you may want to configure for an added key. If you are running a modern distribution the custom agent has been removed and replaced with the stock OpenSSH agent which is feature complete. -=== OpenSSH agent on macOS +=== OpenSSH Agent on macOS Apple has made OpenSSH an integrated part of macOS with automatic agent startup when it is first used. No further configuration is needed. -=== OpenSSH agent and Pageant on Windows +=== OpenSSH Agent and Pageant on Windows The SSH Agent integration on Windows supports both _PuTTY Pageant_ and _OpenSSH for Windows 10_. Since Pageant is currently still the most widely used implementation and is easily installable on any version of Windows, it is the default on KeePassXC. However, Microsoft includes a native OpenSSH client implementation with Windows 10 since autumn 2018 that can be used instead. If you would like to self-manage your OpenSSH version you can use the builds offered via their official https://github.com/powershell/Win32-OpenSSH[GitHub repository]. @@ -61,7 +61,7 @@ Alternatively, you can use a _Windows PowerShell_ running as _Administrator_ to KeePassXC and other compatible tools can now use the Windows OpenSSH agent. To use it with KeePassXC, update the settings explained in <>. -=== Setting up SSH Agent integration +=== Setup SSH Agent Integration By default the SSH Agent integration plugin is disabled. To enable integration, follow the steps below to access the settings: @@ -78,10 +78,10 @@ On Windows, you have the option to select _Pageant_ and/or _OpenSSH for Windows_ If the value of _SSH_AUTH_SOCK_ is empty it means the agent is not properly configured and KeePassXC will be unable to connect to it unless you provide a static override path to the socket. -=== Generating a key to use with KeePassXC +=== Generating an SSH Key KeePassXC only supports keys in the _OpenSSH_ format. On Windows, _PuTTYgen_ saves keys in its own format by default and you will need to convert them to OpenSSH format before being used. In this guide we are going to generate a standard RSA key in the default size. -==== Generating a key on Linux or macOS with _ssh-keygen_ +==== Generating a key on Linux or macOS Open a terminal window and type the following command to generate a key: $ ssh-keygen -o -f keepassxc -C johndoe@example @@ -116,13 +116,13 @@ With KeePassXC you only need the first file listed. ==== Generating a key on Windows On Windows you can generate key pairs with _PuTTYgen_ and with _ssh-keygen_, depending on whether you installed PuTTY and your Windows version. -===== Using _PuTTYgen_ +===== Using PuTTYgen Please read the manual on how to use _PuTTYgen_ for details on generate a key: https://the.earth.li/~sgtatham/putty/0.74/htmldoc/Chapter8.html#pubkey-puttygen. Once generated, you must save the key in the new OpenSSH format, see image below. .Generating a key with _PuTTYgen_ image::sshagent_puttygen.png[,70%] -===== Using _ssh-keygen_ +===== Using ssh-keygen Open _Command Prompt_ or _Windows PowerShell_ and type the following command to generate a key: PS C:\Users\user> ssh-keygen.exe -o -f keepassxc -C johndoe@example @@ -159,7 +159,7 @@ Now we can see two files were generated: With KeePassXC you only need the first file listed. -=== Configuring an entry to use SSH Agent +=== Adding SSH Key to an Entry The last step is to setup an entry to contain the SSH Agent settings and key file you generated. 1. Create a new entry, or open an existing entry in edit mode. diff --git a/docs/topics/UserInterface.adoc b/docs/topics/UserInterface.adoc index 456c09ea6..66a06fafb 100644 --- a/docs/topics/UserInterface.adoc +++ b/docs/topics/UserInterface.adoc @@ -12,11 +12,11 @@ image::main_interface.png[] *(A) Groups* – Organize your entries into discrete groups to bring order to all of your sensitive information. Groups can be nested under each other to create a hierarchy. Settings from parent groups get applied to their children. You can hide this panel on the View menu. -*(B) Tags* – Dynamic groups of entries that can be quickly displayed with one click. Any number of custom tags can be added when editing an entry. This panel also includes useful pre-defined searches, such as finding expired and weak passwords. +*(B) Searches and Tags* – Dynamic groups of entries that can be quickly displayed with one click. Any number of custom tags can be added when editing an entry. This panel also includes useful pre-defined and custom saved searches, such as finding expired and weak passwords. -*\(C) Entries* – Entries contain all the information you want to store for a website or application you are storing in KeePassXC. This view shows all the entries in the selected group. Each column can be resized, reordered, and shown or hidden based on your preference. Right-click the header row to see all available options. +*\(C) Entries* – Entries contain all the information for a website or application you are storing in KeePassXC. This view shows all the entries in the selected group. Each column can be resized, reordered, and shown or hidden based on your preference. Right-click the header row to see all available options. -*(D) Preview* – Shows a preview of the selected group or entry. You can temporarily hide this preview using the close button on the right hand side or completely disabled in the application settings. +*(D) Preview* – Shows a preview of the selected group or entry. You can interact with most information stored in an entry from here without opening the entry for editing. You can temporarily hide this preview using the down-arrow button on the right hand side or completely disable it from the View menu. TIP: You can enable double-click copying of entry username and password in the Application Security Settings. This is turned off by default starting with version 2.7.0. @@ -29,13 +29,17 @@ image::toolbar.png[] *(A) Database* – Open Database, Save Database, Lock Database + *(B) Entries* – Create Entry, Edit Entry, Delete Selected Entries + *\(C) Entry Data* – Copy Username, Copy Password, Copy URL, Perform Auto-Type + -*(D) Tools* – Password Generator, Application Settings + +*(D) Tools* – Database Settings, Reports, Password Generator, Application Settings + *(E) Search* -=== Application Settings -Users can configure KeePassXC to their personal tastes with a wide variety of general and security settings that apply to the whole application. These settings are accessible from _Tools_ -> _Settings_ or the cog wheel icon from the toolbar. Settings include: startup options, file management, entry management, user interface, language, security timeouts, and convenience. +=== Screenshot Security +By default, KeePassXC prevents recordings and screenshots of the application window on Windows and macOS. This prevents inadvertent spillage of information during meetings and disallows other applications to capture the window contents. If you would like to enable screen capture temporarily, navigate to _View_ menu and select _Allow Screen Capture_. Alternatively, you can start the application with the `--allow-screencapture` command line flag. -==== Setting the Theme + +=== View Options +You can customize the appearance of KeePassXC to your liking. The following options are available in the _View_ menu: + +==== Themes KeePassXC ships with light and dark themes specifically designed to meet accessibility standards. In most cases, the appropriate theme for your system will be determined automatically, but you can always set a specific theme by using the _View_ menu. When a new theme is selected you will be prompted to restart KeePassXC to apply the theme immediately. .Setting the theme @@ -47,8 +51,8 @@ For users with smaller screens or those who desire seeing more entries at once, .Compact mode comparison image::compact_mode_comparison.png[] -=== Screenshot Security -By default, KeePassXC prevents recordings and screenshots of the application window on Windows and macOS. This prevents inadvertent spillage of information during meetings and disallows other applications to capture the window contents. If you would like to enable screen capture, you must start the application with the `--allow-screencapture` command line flag. +=== Application Settings +Users can configure KeePassXC to their personal tastes with a wide variety of general and security settings that apply to the whole application. These settings are accessible from _Tools_ -> _Settings_ or the cog wheel icon from the toolbar. Settings include: startup options, file management, entry management, user interface, language, security controls, and integration settings (Auto-Type, Browser, etc). === Keyboard Shortcuts include::KeyboardShortcuts.adoc[tag=content, leveloffset=+1] @@ -77,6 +81,7 @@ Arguments: filename(s) filenames of the password databases to open (*.kdbx) ---- +=== Environment Variables Additionally, the following environment variables may be useful when running the application: [grid=rows, frame=none, width=75%] @@ -91,5 +96,17 @@ Additionally, the following environment variables may be useful when running the |QT_SCREEN_SCALE_FACTORS [list] | Specifies scale factors for each screen. See https://doc.qt.io/qt-5/highdpi.html#high-dpi-support-in-qt |QT_SCALE_FACTOR_ROUNDING_POLICY | Control device pixel ratio rounding to the nearest integer. See https://doc.qt.io/qt-5/highdpi.html#high-dpi-support-in-qt |=== + +=== Installer Options +The following options can be set when running the Windows Installer MSI in an unattended installation: + +* *LAUNCHAPPONEXIT* – Launch KeePassXC after install (default ON) +* *AUTOSTARTPROGRAM* – KeePassXC will auto-start on login (default ON) +* *INSTALLDESKTOPSHORTCUT* – A desktop icon will be installed (default OFF) + +Example: `msiexec.exe /q /i KeePassXC-Y.Y.Y-WinZZ.msi AUTOSTARTPROGRAM=0` + +== Command Line Tool +KeePassXC comes with the command line tool *keepassxc-cli* to access, view, and manipulate your database directly from a terminal window. The tool is documented through a separate man page, which can be shown using `man keepassxc-cli`, or through the on-demand help using `keepassxc-cli [command] -h`. An online version of the man page is https://github.com/keepassxreboot/keepassxc/blob/latest/docs/man/keepassxc-cli.1.adoc[available on GitHub]. // end::advanced[] // end::content[] diff --git a/docs/topics/Welcome.adoc b/docs/topics/Welcome.adoc index b10b04f3d..65de19a5f 100644 --- a/docs/topics/Welcome.adoc +++ b/docs/topics/Welcome.adoc @@ -26,12 +26,13 @@ KeePassXC has numerous features for novice and power users alike. This guide wil ** Password generator ** Auto-Type passwords into applications ** Browser integration with Google Chrome, Mozilla Firefox, Microsoft Edge, Chromium, Vivaldi, Brave, and Tor-Browser + ** Support for passkeys using the browser integration ** Entry icon download - ** Import databases from CSV, 1Password, and KeePass1 formats + ** Import databases from CSV, 1Password, Bitwarden, Proton Pass, and KeePass1 formats * Advanced Features ** Database reports (password health, HIBP, and statistics) - ** Database export to CSV and HTML formats + ** Database export to CSV, XML, and HTML formats ** TOTP storage and generation ** Field references between entries ** File attachments and custom attributes diff --git a/release-tool.ps1 b/release-tool.ps1 index fe39cdcc3..c9db231f6 100644 --- a/release-tool.ps1 +++ b/release-tool.ps1 @@ -351,7 +351,7 @@ if ($Merge) { # Find Visual Studio and establish build environment Invoke-VSToolchain $VSToolChain $SourceDir -Arch "amd64" - if ($SignBuild && !$SignCert) { + if ($SignBuild -and !$SignCert) { $SignCert = Find-SignCert } @@ -457,212 +457,209 @@ if ($Merge) { } # SIG # Begin signature block -# MIIm2gYJKoZIhvcNAQcCoIImyzCCJscCAQExDzANBglghkgBZQMEAgEFADB5Bgor +# MIImVAYJKoZIhvcNAQcCoIImRTCCJkECAQExDzANBglghkgBZQMEAgEFADB5Bgor # BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG -# KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCDuejql+mhHrYzE -# MGUrjGMbUzkTkzwhj8dkNuT2x9j8+KCCH8cwggVvMIIEV6ADAgECAhBI/JO0YFWU -# jTanyYqJ1pQWMA0GCSqGSIb3DQEBDAUAMHsxCzAJBgNVBAYTAkdCMRswGQYDVQQI -# DBJHcmVhdGVyIE1hbmNoZXN0ZXIxEDAOBgNVBAcMB1NhbGZvcmQxGjAYBgNVBAoM -# EUNvbW9kbyBDQSBMaW1pdGVkMSEwHwYDVQQDDBhBQUEgQ2VydGlmaWNhdGUgU2Vy -# dmljZXMwHhcNMjEwNTI1MDAwMDAwWhcNMjgxMjMxMjM1OTU5WjBWMQswCQYDVQQG -# EwJHQjEYMBYGA1UEChMPU2VjdGlnbyBMaW1pdGVkMS0wKwYDVQQDEyRTZWN0aWdv -# IFB1YmxpYyBDb2RlIFNpZ25pbmcgUm9vdCBSNDYwggIiMA0GCSqGSIb3DQEBAQUA -# A4ICDwAwggIKAoICAQCN55QSIgQkdC7/FiMCkoq2rjaFrEfUI5ErPtx94jGgUW+s -# hJHjUoq14pbe0IdjJImK/+8Skzt9u7aKvb0Ffyeba2XTpQxpsbxJOZrxbW6q5KCD -# J9qaDStQ6Utbs7hkNqR+Sj2pcaths3OzPAsM79szV+W+NDfjlxtd/R8SPYIDdub7 -# P2bSlDFp+m2zNKzBenjcklDyZMeqLQSrw2rq4C+np9xu1+j/2iGrQL+57g2extme -# me/G3h+pDHazJyCh1rr9gOcB0u/rgimVcI3/uxXP/tEPNqIuTzKQdEZrRzUTdwUz -# T2MuuC3hv2WnBGsY2HH6zAjybYmZELGt2z4s5KoYsMYHAXVn3m3pY2MeNn9pib6q -# RT5uWl+PoVvLnTCGMOgDs0DGDQ84zWeoU4j6uDBl+m/H5x2xg3RpPqzEaDux5mcz -# mrYI4IAFSEDu9oJkRqj1c7AGlfJsZZ+/VVscnFcax3hGfHCqlBuCF6yH6bbJDoEc -# QNYWFyn8XJwYK+pF9e+91WdPKF4F7pBMeufG9ND8+s0+MkYTIDaKBOq3qgdGnA2T -# OglmmVhcKaO5DKYwODzQRjY1fJy67sPV+Qp2+n4FG0DKkjXp1XrRtX8ArqmQqsV/ -# AZwQsRb8zG4Y3G9i/qZQp7h7uJ0VP/4gDHXIIloTlRmQAOka1cKG8eOO7F/05QID -# AQABo4IBEjCCAQ4wHwYDVR0jBBgwFoAUoBEKIz6W8Qfs4q8p74Klf9AwpLQwHQYD -# VR0OBBYEFDLrkpr/NZZILyhAQnAgNpFcF4XmMA4GA1UdDwEB/wQEAwIBhjAPBgNV -# HRMBAf8EBTADAQH/MBMGA1UdJQQMMAoGCCsGAQUFBwMDMBsGA1UdIAQUMBIwBgYE -# VR0gADAIBgZngQwBBAEwQwYDVR0fBDwwOjA4oDagNIYyaHR0cDovL2NybC5jb21v -# ZG9jYS5jb20vQUFBQ2VydGlmaWNhdGVTZXJ2aWNlcy5jcmwwNAYIKwYBBQUHAQEE -# KDAmMCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC5jb21vZG9jYS5jb20wDQYJKoZI -# hvcNAQEMBQADggEBABK/oe+LdJqYRLhpRrWrJAoMpIpnuDqBv0WKfVIHqI0fTiGF -# OaNrXi0ghr8QuK55O1PNtPvYRL4G2VxjZ9RAFodEhnIq1jIV9RKDwvnhXRFAZ/ZC -# J3LFI+ICOBpMIOLbAffNRk8monxmwFE2tokCVMf8WPtsAO7+mKYulaEMUykfb9gZ -# pk+e96wJ6l2CxouvgKe9gUhShDHaMuwV5KZMPWw5c9QLhTkg4IUaaOGnSDip0TYl -# d8GNGRbFiExmfS9jzpjoad+sPKhdnckcW67Y8y90z7h+9teDnRGWYpquRRPaf9xH -# +9/DUp/mBlXpnYzyOmJRvOwkDynUWICE5EV7WtgwggYaMIIEAqADAgECAhBiHW0M -# UgGeO5B5FSCJIRwKMA0GCSqGSIb3DQEBDAUAMFYxCzAJBgNVBAYTAkdCMRgwFgYD -# VQQKEw9TZWN0aWdvIExpbWl0ZWQxLTArBgNVBAMTJFNlY3RpZ28gUHVibGljIENv -# ZGUgU2lnbmluZyBSb290IFI0NjAeFw0yMTAzMjIwMDAwMDBaFw0zNjAzMjEyMzU5 -# NTlaMFQxCzAJBgNVBAYTAkdCMRgwFgYDVQQKEw9TZWN0aWdvIExpbWl0ZWQxKzAp -# BgNVBAMTIlNlY3RpZ28gUHVibGljIENvZGUgU2lnbmluZyBDQSBSMzYwggGiMA0G -# CSqGSIb3DQEBAQUAA4IBjwAwggGKAoIBgQCbK51T+jU/jmAGQ2rAz/V/9shTUxjI -# ztNsfvxYB5UXeWUzCxEeAEZGbEN4QMgCsJLZUKhWThj/yPqy0iSZhXkZ6Pg2A2NV -# DgFigOMYzB2OKhdqfWGVoYW3haT29PSTahYkwmMv0b/83nbeECbiMXhSOtbam+/3 -# 6F09fy1tsB8je/RV0mIk8XL/tfCK6cPuYHE215wzrK0h1SWHTxPbPuYkRdkP05Zw -# mRmTnAO5/arnY83jeNzhP06ShdnRqtZlV59+8yv+KIhE5ILMqgOZYAENHNX9SJDm -# +qxp4VqpB3MV/h53yl41aHU5pledi9lCBbH9JeIkNFICiVHNkRmq4TpxtwfvjsUe -# dyz8rNyfQJy/aOs5b4s+ac7IH60B+Ja7TVM+EKv1WuTGwcLmoU3FpOFMbmPj8pz4 -# 4MPZ1f9+YEQIQty/NQd/2yGgW+ufflcZ/ZE9o1M7a5Jnqf2i2/uMSWymR8r2oQBM -# dlyh2n5HirY4jKnFH/9gRvd+QOfdRrJZb1sCAwEAAaOCAWQwggFgMB8GA1UdIwQY -# MBaAFDLrkpr/NZZILyhAQnAgNpFcF4XmMB0GA1UdDgQWBBQPKssghyi47G9IritU -# pimqF6TNDDAOBgNVHQ8BAf8EBAMCAYYwEgYDVR0TAQH/BAgwBgEB/wIBADATBgNV -# HSUEDDAKBggrBgEFBQcDAzAbBgNVHSAEFDASMAYGBFUdIAAwCAYGZ4EMAQQBMEsG -# A1UdHwREMEIwQKA+oDyGOmh0dHA6Ly9jcmwuc2VjdGlnby5jb20vU2VjdGlnb1B1 -# YmxpY0NvZGVTaWduaW5nUm9vdFI0Ni5jcmwwewYIKwYBBQUHAQEEbzBtMEYGCCsG -# AQUFBzAChjpodHRwOi8vY3J0LnNlY3RpZ28uY29tL1NlY3RpZ29QdWJsaWNDb2Rl -# U2lnbmluZ1Jvb3RSNDYucDdjMCMGCCsGAQUFBzABhhdodHRwOi8vb2NzcC5zZWN0 -# aWdvLmNvbTANBgkqhkiG9w0BAQwFAAOCAgEABv+C4XdjNm57oRUgmxP/BP6YdURh -# w1aVcdGRP4Wh60BAscjW4HL9hcpkOTz5jUug2oeunbYAowbFC2AKK+cMcXIBD0Zd -# OaWTsyNyBBsMLHqafvIhrCymlaS98+QpoBCyKppP0OcxYEdU0hpsaqBBIZOtBajj -# cw5+w/KeFvPYfLF/ldYpmlG+vd0xqlqd099iChnyIMvY5HexjO2AmtsbpVn0OhNc -# WbWDRF/3sBp6fWXhz7DcML4iTAWS+MVXeNLj1lJziVKEoroGs9Mlizg0bUMbOalO -# hOfCipnx8CaLZeVme5yELg09Jlo8BMe80jO37PU8ejfkP9/uPak7VLwELKxAMcJs -# zkyeiaerlphwoKx1uHRzNyE6bxuSKcutisqmKL5OTunAvtONEoteSiabkPVSZ2z7 -# 6mKnzAfZxCl/3dq3dUNw4rg3sTCggkHSRqTqlLMS7gjrhTqBmzu1L90Y1KWN/Y5J -# KdGvspbOrTfOXyXvmPL6E52z1NZJ6ctuMFBQZH3pwWvqURR8AgQdULUvrxjUYbHH -# j95Ejza63zdrEcxWLDX6xWls/GDnVNueKjWUH3fTv1Y8Wdho698YADR7TNx8X8z2 -# Bev6SivBBOHY+uqiirZtg0y9ShQoPzmCcn63Syatatvx157YK9hlcPmVoa1oDE5/ -# L9Uo2bC5a4CH2RwwggZJMIIEsaADAgECAhAGQz/MzOQzqJLMF7dGpYxlMA0GCSqG -# SIb3DQEBDAUAMFQxCzAJBgNVBAYTAkdCMRgwFgYDVQQKEw9TZWN0aWdvIExpbWl0 -# ZWQxKzApBgNVBAMTIlNlY3RpZ28gUHVibGljIENvZGUgU2lnbmluZyBDQSBSMzYw -# HhcNMjQwMjIzMDAwMDAwWhcNMjcwMjIyMjM1OTU5WjBgMQswCQYDVQQGEwJVUzER -# MA8GA1UECAwIVmlyZ2luaWExHjAcBgNVBAoMFURyb2lkTW9ua2V5IEFwcHMsIExM -# QzEeMBwGA1UEAwwVRHJvaWRNb25rZXkgQXBwcywgTExDMIICIjANBgkqhkiG9w0B -# AQEFAAOCAg8AMIICCgKCAgEAuJtEjRyetghx6Abi1cpMT88uT6nIcTe3AyUvdSkj -# CtUM8Gat0YJfqTxokb9dBzJa7j8YWOUU1Yc4EDXoYYtVRE+1UkdPAcXNMf2hNXGI -# 45iZVwhBPQZBU4QfKltzYqrjAZgDvxeYd68qImjzUfrCY3uZHwEIuCewmNMPpEgb -# djuSXDyBAKKBtaO2iqyaJpqcC39QnDKlXMicDPqqH5fI7wK7Lg9f4BwOsaO4P68I -# 3pOv7L/6E5GR9+hTj6txhxFz/yCbDxN1PUvDsGaXjMmVeP2M95fkwOFwut5yBESD -# IwAGEWUFsTJ32hSmE74+xG6rVqtueayV7U9cGURznSk9ZlTUqQOW9Z4K+pu29gTZ -# 9zVWlONIsQR7QXfGKZWF+Xik6rTujSRTTsK7QNMYzBI6b9v0nD2pEWuGZDXIO5o5 -# N2HzXEFlwxCFY483yWSObHNBp9PFtiDueqv+8vrN+lsirZlDFCxI6hW+F8oYp3Xx -# HdSqxsMRTqbO6dUjH2Tyd0G5fbyT8Rid7DbP6p/apzIrdFOM0kdcKLmppYBp7BIn -# TdjbWJYhtuORIUZQbUOSM71vYCUHj7xkckiYYmkUf0XH8xx8jqgVWseBW63gCEow -# hCEYxaWt0QGyXJ6UrlV4WTUCWzxm45I5OQoofymUvdutKgr9bR3nJ5yS/c+E3Knq -# JhkCAwEAAaOCAYkwggGFMB8GA1UdIwQYMBaAFA8qyyCHKLjsb0iuK1SmKaoXpM0M -# MB0GA1UdDgQWBBQta729krTac3CUndU0S0DdDscjHTAOBgNVHQ8BAf8EBAMCB4Aw -# DAYDVR0TAQH/BAIwADATBgNVHSUEDDAKBggrBgEFBQcDAzBKBgNVHSAEQzBBMDUG -# DCsGAQQBsjEBAgEDAjAlMCMGCCsGAQUFBwIBFhdodHRwczovL3NlY3RpZ28uY29t -# L0NQUzAIBgZngQwBBAEwSQYDVR0fBEIwQDA+oDygOoY4aHR0cDovL2NybC5zZWN0 -# aWdvLmNvbS9TZWN0aWdvUHVibGljQ29kZVNpZ25pbmdDQVIzNi5jcmwweQYIKwYB -# BQUHAQEEbTBrMEQGCCsGAQUFBzAChjhodHRwOi8vY3J0LnNlY3RpZ28uY29tL1Nl -# Y3RpZ29QdWJsaWNDb2RlU2lnbmluZ0NBUjM2LmNydDAjBggrBgEFBQcwAYYXaHR0 -# cDovL29jc3Auc2VjdGlnby5jb20wDQYJKoZIhvcNAQEMBQADggGBAJSy5YPCbh9Z -# suDCKgDuzOWZzNza4/FrA+kT7EitDezYN3S/P0EVc0tPbgYAKfNqY+ihAMyjZHdg -# ybfBWhGzUTDo+HEipcnZ2pgwPadsw23jJ8MN1tdms9iKDakIQ2MVsB7cGFRU8QjL -# ovkPdZkyLcjuYbkiZRoNoKlhmrOOf6n1oCwXVJ9ONJijc+Lr3+4EIqZ39ET2+uI9 -# Wg9Bfd9XrDZfYFEcRJjNzRpCtHb26aIzV/XiMWasHRPaII34SzD0BmaPbsLeGW1U -# GvW3tQcgVNdT/uajegmShVb+c5J5ktRSJ0cqyxmTAYaeMuA6IxG1f6kui1SAFQs2 -# lzlGyEgxgiNGo7cHHN2KidhrBL3U2bGr9Tkdp3gmV+Gj3esCdQzJE4aqmUZvIvHp -# krair4qbLFZRNozAZJn2SIeQa5u2U0ZmvcAr1C7S3JVLP3t9LKE0mlFkV9pbIU97 -# ND3iH3tO0Zb3SvCK/XjO1PZVb8EXsi67wbfMSWAwi2CETDonb7+gBjCCBuwwggTU -# oAMCAQICEDAPb6zdZph0fKlGNqd4LbkwDQYJKoZIhvcNAQEMBQAwgYgxCzAJBgNV -# BAYTAlVTMRMwEQYDVQQIEwpOZXcgSmVyc2V5MRQwEgYDVQQHEwtKZXJzZXkgQ2l0 -# eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMS4wLAYDVQQDEyVVU0VS -# VHJ1c3QgUlNBIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTE5MDUwMjAwMDAw -# MFoXDTM4MDExODIzNTk1OVowfTELMAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0 -# ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEYMBYGA1UEChMPU2VjdGln -# byBMaW1pdGVkMSUwIwYDVQQDExxTZWN0aWdvIFJTQSBUaW1lIFN0YW1waW5nIENB -# MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAyBsBr9ksfoiZfQGYPyCQ -# vZyAIVSTuc+gPlPvs1rAdtYaBKXOR4O168TMSTTL80VlufmnZBYmCfvVMlJ5Lslj -# whObtoY/AQWSZm8hq9VxEHmH9EYqzcRaydvXXUlNclYP3MnjU5g6Kh78zlhJ07/z -# Obu5pCNCrNAVw3+eolzXOPEWsnDTo8Tfs8VyrC4Kd/wNlFK3/B+VcyQ9ASi8Dw1P -# s5EBjm6dJ3VV0Rc7NCF7lwGUr3+Az9ERCleEyX9W4L1GnIK+lJ2/tCCwYH64TfUN -# P9vQ6oWMilZx0S2UTMiMPNMUopy9Jv/TUyDHYGmbWApU9AXn/TGs+ciFF8e4KRmk -# KS9G493bkV+fPzY+DjBnK0a3Na+WvtpMYMyou58NFNQYxDCYdIIhz2JWtSFzEh79 -# qsoIWId3pBXrGVX/0DlULSbuRRo6b83XhPDX8CjFT2SDAtT74t7xvAIo9G3aJ4oG -# 0paH3uhrDvBbfel2aZMgHEqXLHcZK5OVmJyXnuuOwXhWxkQl3wYSmgYtnwNe/YOi -# U2fKsfqNoWTJiJJZy6hGwMnypv99V9sSdvqKQSTUG/xypRSi1K1DHKRJi0E5FAMe -# KfobpSKupcNNgtCN2mu32/cYQFdz8HGj+0p9RTbB942C+rnJDVOAffq2OVgy728Y -# UInXT50zvRq1naHelUF6p4MCAwEAAaOCAVowggFWMB8GA1UdIwQYMBaAFFN5v1qq -# K0rPVIDh2JvAnfKyA2bLMB0GA1UdDgQWBBQaofhhGSAPw0F3RSiO0TVfBhIEVTAO -# BgNVHQ8BAf8EBAMCAYYwEgYDVR0TAQH/BAgwBgEB/wIBADATBgNVHSUEDDAKBggr -# BgEFBQcDCDARBgNVHSAECjAIMAYGBFUdIAAwUAYDVR0fBEkwRzBFoEOgQYY/aHR0 -# cDovL2NybC51c2VydHJ1c3QuY29tL1VTRVJUcnVzdFJTQUNlcnRpZmljYXRpb25B -# dXRob3JpdHkuY3JsMHYGCCsGAQUFBwEBBGowaDA/BggrBgEFBQcwAoYzaHR0cDov -# L2NydC51c2VydHJ1c3QuY29tL1VTRVJUcnVzdFJTQUFkZFRydXN0Q0EuY3J0MCUG -# CCsGAQUFBzABhhlodHRwOi8vb2NzcC51c2VydHJ1c3QuY29tMA0GCSqGSIb3DQEB -# DAUAA4ICAQBtVIGlM10W4bVTgZF13wN6MgstJYQRsrDbKn0qBfW8Oyf0WqC5SVmQ -# KWxhy7VQ2+J9+Z8A70DDrdPi5Fb5WEHP8ULlEH3/sHQfj8ZcCfkzXuqgHCZYXPO0 -# EQ/V1cPivNVYeL9IduFEZ22PsEMQD43k+ThivxMBxYWjTMXMslMwlaTW9JZWCLjN -# XH8Blr5yUmo7Qjd8Fng5k5OUm7Hcsm1BbWfNyW+QPX9FcsEbI9bCVYRm5LPFZgb2 -# 89ZLXq2jK0KKIZL+qG9aJXBigXNjXqC72NzXStM9r4MGOBIdJIct5PwC1j53BLwE -# NrXnd8ucLo0jGLmjwkcd8F3WoXNXBWiap8k3ZR2+6rzYQoNDBaWLpgn/0aGUpk6q -# PQn1BWy30mRa2Coiwkud8TleTN5IPZs0lpoJX47997FSkc4/ifYcobWpdR9xv1tD -# XWU9UIFuq/DQ0/yysx+2mZYm9Dx5i1xkzM3uJ5rloMAMcofBbk1a0x7q8ETmMm8c -# 6xdOlMN4ZSA7D0GqH+mhQZ3+sbigZSo04N6o+TzmwTC7wKBjLPxcFgCo0MR/6hGd -# HgbGpm0yXbQ4CStJB6r97DDa8acvz7f9+tCjhNknnvsBZne5VhDhIG7GrrH5trrI -# NV0zdo7xfCAMKneutaIChrop7rRaALGMq+P5CslUXdS5anSevUiumDCCBvUwggTd -# oAMCAQICEDlMJeF8oG0nqGXiO9kdItQwDQYJKoZIhvcNAQEMBQAwfTELMAkGA1UE -# BhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2Fs -# Zm9yZDEYMBYGA1UEChMPU2VjdGlnbyBMaW1pdGVkMSUwIwYDVQQDExxTZWN0aWdv -# IFJTQSBUaW1lIFN0YW1waW5nIENBMB4XDTIzMDUwMzAwMDAwMFoXDTM0MDgwMjIz -# NTk1OVowajELMAkGA1UEBhMCR0IxEzARBgNVBAgTCk1hbmNoZXN0ZXIxGDAWBgNV -# BAoTD1NlY3RpZ28gTGltaXRlZDEsMCoGA1UEAwwjU2VjdGlnbyBSU0EgVGltZSBT -# dGFtcGluZyBTaWduZXIgIzQwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoIC -# AQCkkyhSS88nh3akKRyZOMDnDtTRHOxoywFk5IrNd7BxZYK8n/yLu7uVmPslEY5a -# iAlmERRYsroiW+b2MvFdLcB6og7g4FZk7aHlgSByIGRBbMfDCPrzfV3vIZrCftcs -# w7oRmB780yAIQrNfv3+IWDKrMLPYjHqWShkTXKz856vpHBYusLA4lUrPhVCrZwMl -# obs46Q9vqVqakSgTNbkf8z3hJMhrsZnoDe+7TeU9jFQDkdD8Lc9VMzh6CRwH0SLg -# Y4anvv3Sg3MSFJuaTAlGvTS84UtQe3LgW/0Zux88ahl7brstRCq+PEzMrIoEk8ZX -# hqBzNiuBl/obm36Ih9hSeYn+bnc317tQn/oYJU8T8l58qbEgWimro0KHd+D0TAJI -# 3VilU6ajoO0ZlmUVKcXtMzAl5paDgZr2YGaQWAeAzUJ1rPu0kdDF3QFAaraoEO72 -# jXq3nnWv06VLGKEMn1ewXiVHkXTNdRLRnG/kXg2b7HUm7v7T9ZIvUoXo2kRRKqLM -# AMqHZkOjGwDvorWWnWKtJwvyG0rJw5RCN4gghKiHrsO6I3J7+FTv+GsnsIX1p0OF -# 2Cs5dNtadwLRpPr1zZw9zB+uUdB7bNgdLRFCU3F0wuU1qi1SEtklz/DT0JFDEtcy -# fZhs43dByP8fJFTvbq3GPlV78VyHOmTxYEsFT++5L+wJEwIDAQABo4IBgjCCAX4w -# HwYDVR0jBBgwFoAUGqH4YRkgD8NBd0UojtE1XwYSBFUwHQYDVR0OBBYEFAMPMciR -# KpO9Y/PRXU2kNA/SlQEYMA4GA1UdDwEB/wQEAwIGwDAMBgNVHRMBAf8EAjAAMBYG -# A1UdJQEB/wQMMAoGCCsGAQUFBwMIMEoGA1UdIARDMEEwNQYMKwYBBAGyMQECAQMI -# MCUwIwYIKwYBBQUHAgEWF2h0dHBzOi8vc2VjdGlnby5jb20vQ1BTMAgGBmeBDAEE -# AjBEBgNVHR8EPTA7MDmgN6A1hjNodHRwOi8vY3JsLnNlY3RpZ28uY29tL1NlY3Rp -# Z29SU0FUaW1lU3RhbXBpbmdDQS5jcmwwdAYIKwYBBQUHAQEEaDBmMD8GCCsGAQUF -# BzAChjNodHRwOi8vY3J0LnNlY3RpZ28uY29tL1NlY3RpZ29SU0FUaW1lU3RhbXBp -# bmdDQS5jcnQwIwYIKwYBBQUHMAGGF2h0dHA6Ly9vY3NwLnNlY3RpZ28uY29tMA0G -# CSqGSIb3DQEBDAUAA4ICAQBMm2VY+uB5z+8VwzJt3jOR63dY4uu9y0o8dd5+lG3D -# IscEld9laWETDPYMnvWJIF7Bh8cDJMrHpfAm3/j4MWUN4OttUVemjIRSCEYcKsLe -# 8tqKRfO+9/YuxH7t+O1ov3pWSOlh5Zo5d7y+upFkiHX/XYUWNCfSKcv/7S3a/76T -# DOxtog3Mw/FuvSGRGiMAUq2X1GJ4KoR5qNc9rCGPcMMkeTqX8Q2jo1tT2KsAulj7 -# NYBPXyhxbBlewoNykK7gxtjymfvqtJJlfAd8NUQdrVgYa2L73mzECqls0yFGcNwv -# jXVMI8JB0HqWO8NL3c2SJnR2XDegmiSeTl9O048P5RNPWURlS0Nkz0j4Z2e5Tb/M -# DbE6MNChPUitemXk7N/gAfCzKko5rMGk+al9NdAyQKCxGSoYIbLIfQVxGksnNqrg -# mByDdefHfkuEQ81D+5CXdioSrEDBcFuZCkD6gG2UYXvIbrnIZ2ckXFCNASDeB/cB -# 1PguEc2dg+X4yiUcRD0n5bCGRyoLG4R2fXtoT4239xO07aAt7nMP2RC6nZksfNd1 -# H48QxJTmfiTllUqIjCfWhWYd+a5kdpHoSP7IVQrtKcMf3jimwBT7Mj34qYNiNsjD -# vgCHHKv6SkIciQPc9Vx8cNldeE7un14g5glqfCsIo0j1FfwET9/NIRx65fWOGtS5 -# QDGCBmkwggZlAgEBMGgwVDELMAkGA1UEBhMCR0IxGDAWBgNVBAoTD1NlY3RpZ28g -# TGltaXRlZDErMCkGA1UEAxMiU2VjdGlnbyBQdWJsaWMgQ29kZSBTaWduaW5nIENB -# IFIzNgIQBkM/zMzkM6iSzBe3RqWMZTANBglghkgBZQMEAgEFAKCBhDAYBgorBgEE -# AYI3AgEMMQowCKACgAChAoAAMBkGCSqGSIb3DQEJAzEMBgorBgEEAYI3AgEEMBwG -# CisGAQQBgjcCAQsxDjAMBgorBgEEAYI3AgEVMC8GCSqGSIb3DQEJBDEiBCCn5BDd -# F+7Q6LMoJuJxenFHgWAZjm1CET9oBKnlZKClzjANBgkqhkiG9w0BAQEFAASCAgAS -# ypiTBQb39I43fGdH6t2OYAl53TSbJfPG99/11OYS+6nMTKhy7dHtzzgMFxBQmL/L -# P4eJJMqh1yIYEjrjhNLLddRhVP2lfsuQ1OkLVx5lS8M32I3SzpskOe+SywMLDYJy -# sYHEcZkyQX0Q2J/RGzF8/tDcltZodYEdZrQdaAKo7bGv1JcYpW7B6JZnNjquE90d -# WVNAsQ6Mc3kzkjbs2qDaRAdkOmX5uENWbNf1GgTRpud7Ic5hMyb4v9qfWAptlFuO -# pLHyuINNsBuTfzD/cGVR9qecDPIE90UnHQHZWws9U+m84CzAmqpptp4VhrAWc7Hc -# bHsbmg4tGA41ythKyERpW9YlwID6fJYMigEVmJihXdM/qRGO2XdfbPAr0C0AMPIV -# re8r86BJw1lxJJYL2gsS/ttgrnW2C8aFq+IxxXWnv/7maPG69K/jmRLQGZuLIZCl -# 7rT6hob37zZMsdnqDZ0DjJb/FGonJr7GpyeMEWPy8eVwZydMbC9hBl8HNgQ04sp7 -# ouskM1nCco9DV+d1Y6Oyje6IylZjD+xgX7VfsDa2O3Lw27cfyxJBW359meYHytkJ -# oYqh4Y4fC9YlYTD3913ryqTbPaWtWjvFV+GR8biHxDoTmTRuNaeN6RDyyZJkdON7 -# CnR/8X8y4C9BXdesvjfIdhHZsGwLJcZ87cnYGb7oYqGCA0swggNHBgkqhkiG9w0B -# CQYxggM4MIIDNAIBATCBkTB9MQswCQYDVQQGEwJHQjEbMBkGA1UECBMSR3JlYXRl -# ciBNYW5jaGVzdGVyMRAwDgYDVQQHEwdTYWxmb3JkMRgwFgYDVQQKEw9TZWN0aWdv -# IExpbWl0ZWQxJTAjBgNVBAMTHFNlY3RpZ28gUlNBIFRpbWUgU3RhbXBpbmcgQ0EC -# EDlMJeF8oG0nqGXiO9kdItQwDQYJYIZIAWUDBAICBQCgeTAYBgkqhkiG9w0BCQMx -# CwYJKoZIhvcNAQcBMBwGCSqGSIb3DQEJBTEPFw0yNDA0MjgyMjE0MzdaMD8GCSqG -# SIb3DQEJBDEyBDARWlO4ZY7Qij7x/efLB7SJrHgfXJwezYW7sskwZhfhnoQ8JQ8Q -# HfefvIk4nF1+1PkwDQYJKoZIhvcNAQEBBQAEggIAWpBgtEaYVRayRmCTjyOoKg0b -# 2vXn3dqpcpckspX4t58xHLbhapGm3Akg9N6C0xZWm9qQ9vhjoOeuLZ0Z+017JRUe -# YExYYIYcyNGlxyt/uXiBst8KiAFFzn6RwIjycQcsnOsGRBAz2E9/k7wGtdg8kqBI -# Q71cDl+seRjWVcTR4JgthphZuRTKS1Jxn3tjDNJuK+LFo4jL38ojxhhdOnb3xzZ0 -# M1AQ+l2YuDxBX4H9aZsbiTfdI1mxvmPgmZbq4fjV28TUCiBhD1UYuHUPN3Ff9Fwo -# 9BMbTLvKqED8Mm9A25S4M8kVZsGt8j3EAt0AJaWbdHLpLC0l0ykDAcSiwZNYsdMu -# vN0q6z5knfhKv4M8FXQ2wu8pbPww7/4kBqqy9L8VMI8UIazG9Z/R7yhkZjEz3jgc -# a/VZMcsDn41B79/9eSx4wED7NYtc0T6DB8WFH1a2CqlORSHnRolnms+VjWerfmZP -# a9lV7Sk1gGZ+MePsWwXj7liURI/ubTtPtxWElWuYookkQMmrOJYj+IZCW4RvV3I3 -# utzHUwfbBaON3Mq46ADayLxKP2SE9j3JXpl4mZeWXdYUrywt2TgQktCXT7iZOinl -# dbx1tso5uDAj1DQDiTm4Nps+UWjyo2bZB/g1ONMqxPDIuY75HryfmJDlvCMp80Tk -# cJchA5s/dVwNSWKti4Q= +# KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCCRMgDV7DQ6PzRo +# 3ULpsxL1VU2JvIFnZPXlxq/hkfU2Y6CCH2owggYUMIID/KADAgECAhB6I67aU2mW +# D5HIPlz0x+M/MA0GCSqGSIb3DQEBDAUAMFcxCzAJBgNVBAYTAkdCMRgwFgYDVQQK +# Ew9TZWN0aWdvIExpbWl0ZWQxLjAsBgNVBAMTJVNlY3RpZ28gUHVibGljIFRpbWUg +# U3RhbXBpbmcgUm9vdCBSNDYwHhcNMjEwMzIyMDAwMDAwWhcNMzYwMzIxMjM1OTU5 +# WjBVMQswCQYDVQQGEwJHQjEYMBYGA1UEChMPU2VjdGlnbyBMaW1pdGVkMSwwKgYD +# VQQDEyNTZWN0aWdvIFB1YmxpYyBUaW1lIFN0YW1waW5nIENBIFIzNjCCAaIwDQYJ +# KoZIhvcNAQEBBQADggGPADCCAYoCggGBAM2Y2ENBq26CK+z2M34mNOSJjNPvIhKA +# VD7vJq+MDoGD46IiM+b83+3ecLvBhStSVjeYXIjfa3ajoW3cS3ElcJzkyZlBnwDE +# JuHlzpbN4kMH2qRBVrjrGJgSlzzUqcGQBaCxpectRGhhnOSwcjPMI3G0hedv2eNm +# GiUbD12OeORN0ADzdpsQ4dDi6M4YhoGE9cbY11XxM2AVZn0GiOUC9+XE0wI7CQKf +# OUfigLDn7i/WeyxZ43XLj5GVo7LDBExSLnh+va8WxTlA+uBvq1KO8RSHUQLgzb1g +# bL9Ihgzxmkdp2ZWNuLc+XyEmJNbD2OIIq/fWlwBp6KNL19zpHsODLIsgZ+WZ1AzC +# s1HEK6VWrxmnKyJJg2Lv23DlEdZlQSGdF+z+Gyn9/CRezKe7WNyxRf4e4bwUtrYE +# 2F5Q+05yDD68clwnweckKtxRaF0VzN/w76kOLIaFVhf5sMM/caEZLtOYqYadtn03 +# 4ykSFaZuIBU9uCSrKRKTPJhWvXk4CllgrwIDAQABo4IBXDCCAVgwHwYDVR0jBBgw +# FoAU9ndq3T/9ARP/FqFsggIv0Ao9FCUwHQYDVR0OBBYEFF9Y7UwxeqJhQo1SgLqz +# YZcZojKbMA4GA1UdDwEB/wQEAwIBhjASBgNVHRMBAf8ECDAGAQH/AgEAMBMGA1Ud +# JQQMMAoGCCsGAQUFBwMIMBEGA1UdIAQKMAgwBgYEVR0gADBMBgNVHR8ERTBDMEGg +# P6A9hjtodHRwOi8vY3JsLnNlY3RpZ28uY29tL1NlY3RpZ29QdWJsaWNUaW1lU3Rh +# bXBpbmdSb290UjQ2LmNybDB8BggrBgEFBQcBAQRwMG4wRwYIKwYBBQUHMAKGO2h0 +# dHA6Ly9jcnQuc2VjdGlnby5jb20vU2VjdGlnb1B1YmxpY1RpbWVTdGFtcGluZ1Jv +# b3RSNDYucDdjMCMGCCsGAQUFBzABhhdodHRwOi8vb2NzcC5zZWN0aWdvLmNvbTAN +# BgkqhkiG9w0BAQwFAAOCAgEAEtd7IK0ONVgMnoEdJVj9TC1ndK/HYiYh9lVUacah +# RoZ2W2hfiEOyQExnHk1jkvpIJzAMxmEc6ZvIyHI5UkPCbXKspioYMdbOnBWQUn73 +# 3qMooBfIghpR/klUqNxx6/fDXqY0hSU1OSkkSivt51UlmJElUICZYBodzD3M/SFj +# eCP59anwxs6hwj1mfvzG+b1coYGnqsSz2wSKr+nDO+Db8qNcTbJZRAiSazr7KyUJ +# Go1c+MScGfG5QHV+bps8BX5Oyv9Ct36Y4Il6ajTqV2ifikkVtB3RNBUgwu/mSiSU +# ice/Jp/q8BMk/gN8+0rNIE+QqU63JoVMCMPY2752LmESsRVVoypJVt8/N3qQ1c6F +# ibbcRabo3azZkcIdWGVSAdoLgAIxEKBeNh9AQO1gQrnh1TA8ldXuJzPSuALOz1Uj +# b0PCyNVkWk7hkhVHfcvBfI8NtgWQupiaAeNHe0pWSGH2opXZYKYG4Lbukg7HpNi/ +# KqJhue2Keak6qH9A8CeEOB7Eob0Zf+fU+CCQaL0cJqlmnx9HCDxF+3BLbUufrV64 +# EbTI40zqegPZdA+sXCmbcZy6okx/SjwsusWRItFA3DE8MORZeFb6BmzBtqKJ7l93 +# 9bbKBy2jvxcJI98Va95Q5JnlKor3m0E7xpMeYRriWklUPsetMSf2NvUQa/E5vVye +# fQIwggYaMIIEAqADAgECAhBiHW0MUgGeO5B5FSCJIRwKMA0GCSqGSIb3DQEBDAUA +# MFYxCzAJBgNVBAYTAkdCMRgwFgYDVQQKEw9TZWN0aWdvIExpbWl0ZWQxLTArBgNV +# BAMTJFNlY3RpZ28gUHVibGljIENvZGUgU2lnbmluZyBSb290IFI0NjAeFw0yMTAz +# MjIwMDAwMDBaFw0zNjAzMjEyMzU5NTlaMFQxCzAJBgNVBAYTAkdCMRgwFgYDVQQK +# Ew9TZWN0aWdvIExpbWl0ZWQxKzApBgNVBAMTIlNlY3RpZ28gUHVibGljIENvZGUg +# U2lnbmluZyBDQSBSMzYwggGiMA0GCSqGSIb3DQEBAQUAA4IBjwAwggGKAoIBgQCb +# K51T+jU/jmAGQ2rAz/V/9shTUxjIztNsfvxYB5UXeWUzCxEeAEZGbEN4QMgCsJLZ +# UKhWThj/yPqy0iSZhXkZ6Pg2A2NVDgFigOMYzB2OKhdqfWGVoYW3haT29PSTahYk +# wmMv0b/83nbeECbiMXhSOtbam+/36F09fy1tsB8je/RV0mIk8XL/tfCK6cPuYHE2 +# 15wzrK0h1SWHTxPbPuYkRdkP05ZwmRmTnAO5/arnY83jeNzhP06ShdnRqtZlV59+ +# 8yv+KIhE5ILMqgOZYAENHNX9SJDm+qxp4VqpB3MV/h53yl41aHU5pledi9lCBbH9 +# JeIkNFICiVHNkRmq4TpxtwfvjsUedyz8rNyfQJy/aOs5b4s+ac7IH60B+Ja7TVM+ +# EKv1WuTGwcLmoU3FpOFMbmPj8pz44MPZ1f9+YEQIQty/NQd/2yGgW+ufflcZ/ZE9 +# o1M7a5Jnqf2i2/uMSWymR8r2oQBMdlyh2n5HirY4jKnFH/9gRvd+QOfdRrJZb1sC +# AwEAAaOCAWQwggFgMB8GA1UdIwQYMBaAFDLrkpr/NZZILyhAQnAgNpFcF4XmMB0G +# A1UdDgQWBBQPKssghyi47G9IritUpimqF6TNDDAOBgNVHQ8BAf8EBAMCAYYwEgYD +# VR0TAQH/BAgwBgEB/wIBADATBgNVHSUEDDAKBggrBgEFBQcDAzAbBgNVHSAEFDAS +# MAYGBFUdIAAwCAYGZ4EMAQQBMEsGA1UdHwREMEIwQKA+oDyGOmh0dHA6Ly9jcmwu +# c2VjdGlnby5jb20vU2VjdGlnb1B1YmxpY0NvZGVTaWduaW5nUm9vdFI0Ni5jcmww +# ewYIKwYBBQUHAQEEbzBtMEYGCCsGAQUFBzAChjpodHRwOi8vY3J0LnNlY3RpZ28u +# Y29tL1NlY3RpZ29QdWJsaWNDb2RlU2lnbmluZ1Jvb3RSNDYucDdjMCMGCCsGAQUF +# BzABhhdodHRwOi8vb2NzcC5zZWN0aWdvLmNvbTANBgkqhkiG9w0BAQwFAAOCAgEA +# Bv+C4XdjNm57oRUgmxP/BP6YdURhw1aVcdGRP4Wh60BAscjW4HL9hcpkOTz5jUug +# 2oeunbYAowbFC2AKK+cMcXIBD0ZdOaWTsyNyBBsMLHqafvIhrCymlaS98+QpoBCy +# KppP0OcxYEdU0hpsaqBBIZOtBajjcw5+w/KeFvPYfLF/ldYpmlG+vd0xqlqd099i +# ChnyIMvY5HexjO2AmtsbpVn0OhNcWbWDRF/3sBp6fWXhz7DcML4iTAWS+MVXeNLj +# 1lJziVKEoroGs9Mlizg0bUMbOalOhOfCipnx8CaLZeVme5yELg09Jlo8BMe80jO3 +# 7PU8ejfkP9/uPak7VLwELKxAMcJszkyeiaerlphwoKx1uHRzNyE6bxuSKcutisqm +# KL5OTunAvtONEoteSiabkPVSZ2z76mKnzAfZxCl/3dq3dUNw4rg3sTCggkHSRqTq +# lLMS7gjrhTqBmzu1L90Y1KWN/Y5JKdGvspbOrTfOXyXvmPL6E52z1NZJ6ctuMFBQ +# ZH3pwWvqURR8AgQdULUvrxjUYbHHj95Ejza63zdrEcxWLDX6xWls/GDnVNueKjWU +# H3fTv1Y8Wdho698YADR7TNx8X8z2Bev6SivBBOHY+uqiirZtg0y9ShQoPzmCcn63 +# Syatatvx157YK9hlcPmVoa1oDE5/L9Uo2bC5a4CH2RwwggZJMIIEsaADAgECAhAG +# Qz/MzOQzqJLMF7dGpYxlMA0GCSqGSIb3DQEBDAUAMFQxCzAJBgNVBAYTAkdCMRgw +# FgYDVQQKEw9TZWN0aWdvIExpbWl0ZWQxKzApBgNVBAMTIlNlY3RpZ28gUHVibGlj +# IENvZGUgU2lnbmluZyBDQSBSMzYwHhcNMjQwMjIzMDAwMDAwWhcNMjcwMjIyMjM1 +# OTU5WjBgMQswCQYDVQQGEwJVUzERMA8GA1UECAwIVmlyZ2luaWExHjAcBgNVBAoM +# FURyb2lkTW9ua2V5IEFwcHMsIExMQzEeMBwGA1UEAwwVRHJvaWRNb25rZXkgQXBw +# cywgTExDMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAuJtEjRyetghx +# 6Abi1cpMT88uT6nIcTe3AyUvdSkjCtUM8Gat0YJfqTxokb9dBzJa7j8YWOUU1Yc4 +# EDXoYYtVRE+1UkdPAcXNMf2hNXGI45iZVwhBPQZBU4QfKltzYqrjAZgDvxeYd68q +# ImjzUfrCY3uZHwEIuCewmNMPpEgbdjuSXDyBAKKBtaO2iqyaJpqcC39QnDKlXMic +# DPqqH5fI7wK7Lg9f4BwOsaO4P68I3pOv7L/6E5GR9+hTj6txhxFz/yCbDxN1PUvD +# sGaXjMmVeP2M95fkwOFwut5yBESDIwAGEWUFsTJ32hSmE74+xG6rVqtueayV7U9c +# GURznSk9ZlTUqQOW9Z4K+pu29gTZ9zVWlONIsQR7QXfGKZWF+Xik6rTujSRTTsK7 +# QNMYzBI6b9v0nD2pEWuGZDXIO5o5N2HzXEFlwxCFY483yWSObHNBp9PFtiDueqv+ +# 8vrN+lsirZlDFCxI6hW+F8oYp3XxHdSqxsMRTqbO6dUjH2Tyd0G5fbyT8Rid7DbP +# 6p/apzIrdFOM0kdcKLmppYBp7BInTdjbWJYhtuORIUZQbUOSM71vYCUHj7xkckiY +# YmkUf0XH8xx8jqgVWseBW63gCEowhCEYxaWt0QGyXJ6UrlV4WTUCWzxm45I5OQoo +# fymUvdutKgr9bR3nJ5yS/c+E3KnqJhkCAwEAAaOCAYkwggGFMB8GA1UdIwQYMBaA +# FA8qyyCHKLjsb0iuK1SmKaoXpM0MMB0GA1UdDgQWBBQta729krTac3CUndU0S0Dd +# DscjHTAOBgNVHQ8BAf8EBAMCB4AwDAYDVR0TAQH/BAIwADATBgNVHSUEDDAKBggr +# BgEFBQcDAzBKBgNVHSAEQzBBMDUGDCsGAQQBsjEBAgEDAjAlMCMGCCsGAQUFBwIB +# FhdodHRwczovL3NlY3RpZ28uY29tL0NQUzAIBgZngQwBBAEwSQYDVR0fBEIwQDA+ +# oDygOoY4aHR0cDovL2NybC5zZWN0aWdvLmNvbS9TZWN0aWdvUHVibGljQ29kZVNp +# Z25pbmdDQVIzNi5jcmwweQYIKwYBBQUHAQEEbTBrMEQGCCsGAQUFBzAChjhodHRw +# Oi8vY3J0LnNlY3RpZ28uY29tL1NlY3RpZ29QdWJsaWNDb2RlU2lnbmluZ0NBUjM2 +# LmNydDAjBggrBgEFBQcwAYYXaHR0cDovL29jc3Auc2VjdGlnby5jb20wDQYJKoZI +# hvcNAQEMBQADggGBAJSy5YPCbh9ZsuDCKgDuzOWZzNza4/FrA+kT7EitDezYN3S/ +# P0EVc0tPbgYAKfNqY+ihAMyjZHdgybfBWhGzUTDo+HEipcnZ2pgwPadsw23jJ8MN +# 1tdms9iKDakIQ2MVsB7cGFRU8QjLovkPdZkyLcjuYbkiZRoNoKlhmrOOf6n1oCwX +# VJ9ONJijc+Lr3+4EIqZ39ET2+uI9Wg9Bfd9XrDZfYFEcRJjNzRpCtHb26aIzV/Xi +# MWasHRPaII34SzD0BmaPbsLeGW1UGvW3tQcgVNdT/uajegmShVb+c5J5ktRSJ0cq +# yxmTAYaeMuA6IxG1f6kui1SAFQs2lzlGyEgxgiNGo7cHHN2KidhrBL3U2bGr9Tkd +# p3gmV+Gj3esCdQzJE4aqmUZvIvHpkrair4qbLFZRNozAZJn2SIeQa5u2U0ZmvcAr +# 1C7S3JVLP3t9LKE0mlFkV9pbIU97ND3iH3tO0Zb3SvCK/XjO1PZVb8EXsi67wbfM +# SWAwi2CETDonb7+gBjCCBl0wggTFoAMCAQICEDpSaiyEzlXmHWX8zBLY6YkwDQYJ +# KoZIhvcNAQEMBQAwVTELMAkGA1UEBhMCR0IxGDAWBgNVBAoTD1NlY3RpZ28gTGlt +# aXRlZDEsMCoGA1UEAxMjU2VjdGlnbyBQdWJsaWMgVGltZSBTdGFtcGluZyBDQSBS +# MzYwHhcNMjQwMTE1MDAwMDAwWhcNMzUwNDE0MjM1OTU5WjBuMQswCQYDVQQGEwJH +# QjETMBEGA1UECBMKTWFuY2hlc3RlcjEYMBYGA1UEChMPU2VjdGlnbyBMaW1pdGVk +# MTAwLgYDVQQDEydTZWN0aWdvIFB1YmxpYyBUaW1lIFN0YW1waW5nIFNpZ25lciBS +# MzUwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCN0Wf0wUibvf04STpN +# YYGbw9jcRaVhBDaNBp7jmJaA9dQZW5ighrXGNMYjK7Dey5RIHMqLIbT9z9if753m +# YbojJrKWO4ZP0N5dBT2TwZZaPb8E+hqaDZ8Vy2c+x1NiEwbEzTrPX4W3QFq/zJvD +# DbWKL99qLL42GJQzX3n5wWo60KklfFn+Wb22mOZWYSqkCVGl8aYuE12SqIS4MVO4 +# PUaxXeO+4+48YpQlNqbc/ndTgszRQLF4MjxDPjRDD1M9qvpLTZcTGVzxfViyIToR +# NxPP6DUiZDU6oXARrGwyP9aglPXwYbkqI2dLuf9fiIzBugCDciOly8TPDgBkJmjA +# fILNiGcVEzg+40xUdhxNcaC+6r0juPiR7bzXHh7v/3RnlZuT3ZGstxLfmE7fRMAF +# wbHdDz5gtHLqjSTXDiNF58IxPtvmZPG2rlc+Yq+2B8+5pY+QZn+1vEifI0MDtiA6 +# BxxQuOnj4PnqDaK7NEKwtD1pzoA3jJFuoJiwbatwhDkg1PIjYnMDbDW+wAc9FtRN +# 6pUsO405jaBgigoFZCw9hWjLNqgFVTo7lMb5rVjJ9aSBVVL2dcqzyFW2LdWk5Xdp +# 65oeeOALod7YIIMv1pbqC15R7QCYLxcK1bCl4/HpBbdE5mjy9JR70BHuYx27n4XN +# OZbwrXcG3wZf9gEUk7stbPAoBQIDAQABo4IBjjCCAYowHwYDVR0jBBgwFoAUX1jt +# TDF6omFCjVKAurNhlxmiMpswHQYDVR0OBBYEFGjvpDJJabZSOB3qQzks9BRqngyF +# MA4GA1UdDwEB/wQEAwIGwDAMBgNVHRMBAf8EAjAAMBYGA1UdJQEB/wQMMAoGCCsG +# AQUFBwMIMEoGA1UdIARDMEEwNQYMKwYBBAGyMQECAQMIMCUwIwYIKwYBBQUHAgEW +# F2h0dHBzOi8vc2VjdGlnby5jb20vQ1BTMAgGBmeBDAEEAjBKBgNVHR8EQzBBMD+g +# PaA7hjlodHRwOi8vY3JsLnNlY3RpZ28uY29tL1NlY3RpZ29QdWJsaWNUaW1lU3Rh +# bXBpbmdDQVIzNi5jcmwwegYIKwYBBQUHAQEEbjBsMEUGCCsGAQUFBzAChjlodHRw +# Oi8vY3J0LnNlY3RpZ28uY29tL1NlY3RpZ29QdWJsaWNUaW1lU3RhbXBpbmdDQVIz +# Ni5jcnQwIwYIKwYBBQUHMAGGF2h0dHA6Ly9vY3NwLnNlY3RpZ28uY29tMA0GCSqG +# SIb3DQEBDAUAA4IBgQCw3C7J+k82TIov9slP1e8YTx+fDsa//hJ62Y6SMr2E89rv +# 82y/n8we5W6z5pfBEWozlW7nWp+sdPCdUTFw/YQcqvshH6b9Rvs9qZp5Z+V7nHwP +# TH8yzKwgKzTTG1I1XEXLAK9fHnmXpaDeVeI8K6Lw3iznWZdLQe3zl+Rejdq5l2jU +# 7iUfMkthfhFmi+VVYPkR/BXpV7Ub1QyyWebqkjSHJHRmv3lBYbQyk08/S7TlIeOr +# 9iQ+UN57fJg4QI0yqdn6PyiehS1nSgLwKRs46T8A6hXiSn/pCXaASnds0LsM5OVo +# KYfbgOOlWCvKfwUySWoSgrhncihSBXxH2pAuDV2vr8GOCEaePZc0Dy6O1rYnKjGm +# qm/IRNkJghSMizr1iIOPN+23futBXAhmx8Ji/4NTmyH9K0UvXHiuA2Pa3wZxxR9r +# 9XeIUVb2V8glZay+2ULlc445CzCvVSZV01ZB6bgvCuUuBx079gCcepjnZDCcEuIC +# 5Se4F6yFaZ8RvmiJ4hgwggaCMIIEaqADAgECAhA2wrC9fBs656Oz3TbLyXVoMA0G +# CSqGSIb3DQEBDAUAMIGIMQswCQYDVQQGEwJVUzETMBEGA1UECBMKTmV3IEplcnNl +# eTEUMBIGA1UEBxMLSmVyc2V5IENpdHkxHjAcBgNVBAoTFVRoZSBVU0VSVFJVU1Qg +# TmV0d29yazEuMCwGA1UEAxMlVVNFUlRydXN0IFJTQSBDZXJ0aWZpY2F0aW9uIEF1 +# dGhvcml0eTAeFw0yMTAzMjIwMDAwMDBaFw0zODAxMTgyMzU5NTlaMFcxCzAJBgNV +# BAYTAkdCMRgwFgYDVQQKEw9TZWN0aWdvIExpbWl0ZWQxLjAsBgNVBAMTJVNlY3Rp +# Z28gUHVibGljIFRpbWUgU3RhbXBpbmcgUm9vdCBSNDYwggIiMA0GCSqGSIb3DQEB +# AQUAA4ICDwAwggIKAoICAQCIndi5RWedHd3ouSaBmlRUwHxJBZvMWhUP2ZQQRLRB +# QIF3FJmp1OR2LMgIU14g0JIlL6VXWKmdbmKGRDILRxEtZdQnOh2qmcxGzjqemIk8 +# et8sE6J+N+Gl1cnZocew8eCAawKLu4TRrCoqCAT8uRjDeypoGJrruH/drCio28aq +# IVEn45NZiZQI7YYBex48eL78lQ0BrHeSmqy1uXe9xN04aG0pKG9ki+PC6VEfzutu +# 6Q3IcZZfm00r9YAEp/4aeiLhyaKxLuhKKaAdQjRaf/h6U13jQEV1JnUTCm511n5a +# vv4N+jSVwd+Wb8UMOs4netapq5Q/yGyiQOgjsP/JRUj0MAT9YrcmXcLgsrAimfWY +# 3MzKm1HCxcquinTqbs1Q0d2VMMQyi9cAgMYC9jKc+3mW62/yVl4jnDcw6ULJsBkO +# krcPLUwqj7poS0T2+2JMzPP+jZ1h90/QpZnBkhdtixMiWDVgh60KmLmzXiqJc6lG +# wqoUqpq/1HVHm+Pc2B6+wCy/GwCcjw5rmzajLbmqGygEgaj/OLoanEWP6Y52Hfle +# f3XLvYnhEY4kSirMQhtberRvaI+5YsD3XVxHGBjlIli5u+NrLedIxsE88WzKXqZj +# j9Zi5ybJL2WjeXuOTbswB7XjkZbErg7ebeAQUQiS/uRGZ58NHs57ZPUfECcgJC+v +# 2wIDAQABo4IBFjCCARIwHwYDVR0jBBgwFoAUU3m/WqorSs9UgOHYm8Cd8rIDZssw +# HQYDVR0OBBYEFPZ3at0//QET/xahbIICL9AKPRQlMA4GA1UdDwEB/wQEAwIBhjAP +# BgNVHRMBAf8EBTADAQH/MBMGA1UdJQQMMAoGCCsGAQUFBwMIMBEGA1UdIAQKMAgw +# BgYEVR0gADBQBgNVHR8ESTBHMEWgQ6BBhj9odHRwOi8vY3JsLnVzZXJ0cnVzdC5j +# b20vVVNFUlRydXN0UlNBQ2VydGlmaWNhdGlvbkF1dGhvcml0eS5jcmwwNQYIKwYB +# BQUHAQEEKTAnMCUGCCsGAQUFBzABhhlodHRwOi8vb2NzcC51c2VydHJ1c3QuY29t +# MA0GCSqGSIb3DQEBDAUAA4ICAQAOvmVB7WhEuOWhxdQRh+S3OyWM637ayBeR7djx +# Q8SihTnLf2sABFoB0DFR6JfWS0snf6WDG2gtCGflwVvcYXZJJlFfym1Doi+4PfDP +# 8s0cqlDmdfyGOwMtGGzJ4iImyaz3IBae91g50QyrVbrUoT0mUGQHbRcF57olpfHh +# QEStz5i6hJvVLFV/ueQ21SM99zG4W2tB1ExGL98idX8ChsTwbD/zIExAopoe3l6J +# rzJtPxj8V9rocAnLP2C8Q5wXVVZcbw4x4ztXLsGzqZIiRh5i111TW7HV1AtsQa6v +# Xy633vCAbAOIaKcLAo/IU7sClyZUk62XD0VUnHD+YvVNvIGezjM6CRpcWed/ODip +# tK+evDKPU2K6synimYBaNH49v9Ih24+eYXNtI38byt5kIvh+8aW88WThRpv8lUJK +# aPn37+YHYafob9Rg7LyTrSYpyZoBmwRWSE4W6iPjB7wJjJpH29308ZkpKKdpkiS9 +# WNsf/eeUtvRrtIEiSJHN899L1P4l6zKVsdrUu1FX1T/ubSrsxrYJD+3f3aKg6yxd +# bugot06YwGXXiy5UUGZvOu3lXlxA+fC13dQ5OlL2gIb5lmF6Ii8+CQOYDwXM+yd9 +# dbmocQsHjcRPsccUd5E9FiswEqORvz8g3s+jR3SFCgXhN4wz7NgAnOgpCdUo4uDy +# llU9PzGCBkAwggY8AgEBMGgwVDELMAkGA1UEBhMCR0IxGDAWBgNVBAoTD1NlY3Rp +# Z28gTGltaXRlZDErMCkGA1UEAxMiU2VjdGlnbyBQdWJsaWMgQ29kZSBTaWduaW5n +# IENBIFIzNgIQBkM/zMzkM6iSzBe3RqWMZTANBglghkgBZQMEAgEFAKCBhDAYBgor +# BgEEAYI3AgEMMQowCKACgAChAoAAMBkGCSqGSIb3DQEJAzEMBgorBgEEAYI3AgEE +# MBwGCisGAQQBgjcCAQsxDjAMBgorBgEEAYI3AgEVMC8GCSqGSIb3DQEJBDEiBCCw +# CjBOFSrHIl5SZxVeFP1D+IfXa4B5pNieNHIkm0/SqTANBgkqhkiG9w0BAQEFAASC +# AgAgFK2xkUz0aie9HSo0e4qyDk83CNX9G/GR7+DObTay5l7OYVZIdB2kOZIS8UbH +# 4gMSsjplIVObVyf1DjGGCctq4bFDABL7wpwqm7P3tEjs2d/HK2Yxoe1c8YFTYMJJ +# Vc6Q9l/nZA7ZC/SCH1NyEgK+w3vQ6SARudN8/ZgFVa1P3DdwOADmLD774v3bOUKq +# XKDOySeYD7bkCekPv6yx6DnrWBBsYIKFRv2Yv4duThki4CC1FMgEVTmdBDJIP3R8 +# 1BgXjPvVxYX3aQ9emC3KluyNr/BEPZiVdwBjXCE60n7g/Y8qNgqY0ZaImSpl9MFx +# VkrxE7iNfBcBE8xVCghyDahs1BxyEeEdQk+QlLD1Cv3KGODlyWjgncDAX7fnkC6l +# M7KUttjXGi9uQG3g2dUCX+744wPhRg+DBfch2Em70I0kYsPY6ETyrQogZdi6QzKO +# Hlf/hUW0o9HCc6BrTSL4y8G0mlKVCgUpMOjlrip88bvW05ZUX20arGKxGg1uxFIA +# r7wvQyFn+RvNc0kqWt/xgwp3HAc80ABPCYumLqGwucBWisiMt4P2s+fkLpYJdC/n +# pS/3fRoepfGmv8J1WAIjGiO7e12aDrTQqNP+2RUzkNpy2eRQDL+3VUFQOQqEfkVL +# Y6wpN6nB7olNULhPUlwZChf49v/h+XUxhgHozWN576qoyqGCAyIwggMeBgkqhkiG +# 9w0BCQYxggMPMIIDCwIBATBpMFUxCzAJBgNVBAYTAkdCMRgwFgYDVQQKEw9TZWN0 +# aWdvIExpbWl0ZWQxLDAqBgNVBAMTI1NlY3RpZ28gUHVibGljIFRpbWUgU3RhbXBp +# bmcgQ0EgUjM2AhA6UmoshM5V5h1l/MwS2OmJMA0GCWCGSAFlAwQCAgUAoHkwGAYJ +# KoZIhvcNAQkDMQsGCSqGSIb3DQEHATAcBgkqhkiG9w0BCQUxDxcNMjQwOTE0MDMy +# MTU1WjA/BgkqhkiG9w0BCQQxMgQwwrUMFcAva5866cdprEw/weWm4EfoAA4SCloN +# B50191F7ps9XQIxGfsz+g0vQxzxfMA0GCSqGSIb3DQEBAQUABIICAC3qVFmWQWkL +# kn/AYJPZ3B7Yvwq0P7SqcHO9w5FiV5wsznH6xfvkTzXssQLhKaZdqypnHCTNth8D +# 7mgr6zZYh5CgQQ3SSG2q0xVzs3wanJmZ4g6I7bVeGMLv47tFnCed9G3aP5cywDBn +# vMOiwZnQR1WwM8T6qE4sAb4lKXUYDbIVB1DMRAF3j2rQMAN9e9jF6Ok+ZyQqpBSl +# ve2vBR0TgFXeyidwiz6O2I1FWc1OzwMchbJTANbQqWRKuiQ6gm0Bj/S8dalBb77I +# jxS0Tn7kRH1Sr50ZfWRSxj7H7afsQOKbDHxhWFhctvQfbrmbNj+gHcm9j/rSPpU7 +# zj5OvgKyYQnjiLjCnGBTmSML2ZwvXhPv2XkFQ2yL2nYWTRqLjARdcP62kSrkQxEa +# DLAZ7mcndE+HZVMllBGVI9/H5hkE7jINBU4gNvyqQQqF3xTatJMldyrXCQ6R9wfN +# LsdyFB177vZXLrS1EymCzq1COpbrw3oa/LXP+1hZFhoaOYy00LUnCU5Zjd8UFWIh +# FDj3Z7O/Xz3P8BR4t7PGqUu3x8UbxcsGDH0w0e3pvPmxXiBZlspjNieg073YNKxU +# Yuj0b3cX/cpYH0M0Ne/tXuHwbZthwwll3vytT7Aa+oglejolDQjRc8Gv5KW0dUK3 +# LmVw9eforeFUrTExSEc/0jf29BmZz9do # SIG # End signature block diff --git a/share/CMakeLists.txt b/share/CMakeLists.txt index 90f7e6e68..f120fc6e2 100644 --- a/share/CMakeLists.txt +++ b/share/CMakeLists.txt @@ -58,7 +58,12 @@ if(UNIX AND NOT APPLE AND NOT HAIKU) EXCLUDE PATTERN "actions" EXCLUDE PATTERN "categories" EXCLUDE) endif(KEEPASSXC_DIST_FLATPAK) configure_file(linux/${APP_ID}.desktop.in ${CMAKE_CURRENT_BINARY_DIR}/linux/${APP_ID}.desktop @ONLY) + configure_file(linux/${APP_ID}.policy.in ${CMAKE_CURRENT_BINARY_DIR}/linux/${APP_ID}.policy @ONLY) + install(FILES ${CMAKE_CURRENT_BINARY_DIR}/linux/${APP_ID}.desktop DESTINATION ${CMAKE_INSTALL_DATADIR}/applications) + if("${CMAKE_SYSTEM}" MATCHES "Linux") + install(FILES ${CMAKE_CURRENT_BINARY_DIR}/linux/${APP_ID}.policy DESTINATION ${CMAKE_INSTALL_DATADIR}/polkit-1/actions) + endif() install(FILES linux/${APP_ID}.appdata.xml DESTINATION ${CMAKE_INSTALL_DATADIR}/metainfo) endif(UNIX AND NOT APPLE AND NOT HAIKU) diff --git a/share/demo.kdbx b/share/demo.kdbx index b1a37e99f..0d47152db 100644 Binary files a/share/demo.kdbx and b/share/demo.kdbx differ diff --git a/share/demo.key b/share/demo.key deleted file mode 100644 index d97c5eada..000000000 --- a/share/demo.key +++ /dev/null @@ -1 +0,0 @@ -secret diff --git a/share/demo.old.kdbx b/share/demo.old.kdbx deleted file mode 100644 index 14c034ff8..000000000 Binary files a/share/demo.old.kdbx and /dev/null differ diff --git a/share/demo_readme.md b/share/demo_readme.md new file mode 100644 index 000000000..4553adaf3 --- /dev/null +++ b/share/demo_readme.md @@ -0,0 +1,3 @@ +This is a demo database to showcase some of the features of KeePassXC + +The password to unlock demo.kdbx is: secret diff --git a/share/icons/application/scalable/actions/arrow-collapse-down.svg b/share/icons/application/scalable/actions/arrow-collapse-down.svg new file mode 100644 index 000000000..27cfc42f2 --- /dev/null +++ b/share/icons/application/scalable/actions/arrow-collapse-down.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/share/icons/application/scalable/actions/database-settings.svg b/share/icons/application/scalable/actions/database-settings.svg new file mode 100644 index 000000000..7bd0b9cab --- /dev/null +++ b/share/icons/application/scalable/actions/database-settings.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/share/icons/application/scalable/actions/entry-delete.svg b/share/icons/application/scalable/actions/entry-delete.svg index 66ae96f1b..f052113af 100644 --- a/share/icons/application/scalable/actions/entry-delete.svg +++ b/share/icons/application/scalable/actions/entry-delete.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/share/icons/application/scalable/actions/entry-expire.svg b/share/icons/application/scalable/actions/entry-expire.svg new file mode 100644 index 000000000..a0a9ad53b --- /dev/null +++ b/share/icons/application/scalable/actions/entry-expire.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/share/icons/application/scalable/actions/lock-open-alert.svg b/share/icons/application/scalable/actions/lock-open-alert.svg new file mode 100644 index 000000000..348537f09 --- /dev/null +++ b/share/icons/application/scalable/actions/lock-open-alert.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/share/icons/application/scalable/actions/lock-open.svg b/share/icons/application/scalable/actions/lock-open.svg new file mode 100644 index 000000000..ffe75da95 --- /dev/null +++ b/share/icons/application/scalable/actions/lock-open.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/share/icons/application/scalable/actions/lock.svg b/share/icons/application/scalable/actions/lock.svg new file mode 100644 index 000000000..5c0eb3f66 --- /dev/null +++ b/share/icons/application/scalable/actions/lock.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/share/icons/application/scalable/actions/proton.svg b/share/icons/application/scalable/actions/proton.svg new file mode 100644 index 000000000..89515ddec --- /dev/null +++ b/share/icons/application/scalable/actions/proton.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/share/icons/application/scalable/actions/remote-sync.svg b/share/icons/application/scalable/actions/remote-sync.svg new file mode 100644 index 000000000..77b691b1d --- /dev/null +++ b/share/icons/application/scalable/actions/remote-sync.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/share/icons/application/scalable/actions/reports.svg b/share/icons/application/scalable/actions/reports.svg index 3d62971d2..545352534 100644 --- a/share/icons/application/scalable/actions/reports.svg +++ b/share/icons/application/scalable/actions/reports.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/share/icons/application/scalable/actions/totp-invalid.svg b/share/icons/application/scalable/actions/totp-invalid.svg new file mode 100644 index 000000000..c4146ab84 --- /dev/null +++ b/share/icons/application/scalable/actions/totp-invalid.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/share/icons/icons.qrc b/share/icons/icons.qrc index a846bf7bc..3e82e172d 100644 --- a/share/icons/icons.qrc +++ b/share/icons/icons.qrc @@ -6,6 +6,7 @@ application/256x256/apps/keepassxc.png application/scalable/actions/application-exit.svg + application/scalable/actions/arrow-collapse-down.svg application/scalable/actions/attributes-copy.svg application/scalable/actions/auto-type.svg application/scalable/actions/bitwarden.svg @@ -20,6 +21,7 @@ application/scalable/actions/database-lock-all.svg application/scalable/actions/database-merge.svg application/scalable/actions/database-search.svg + application/scalable/actions/database-settings.svg application/scalable/actions/dialog-close.svg application/scalable/actions/dialog-ok.svg application/scalable/actions/document-close.svg @@ -38,6 +40,7 @@ application/scalable/actions/edit-clear-locationbar-rtl.svg application/scalable/actions/entry-clone.svg application/scalable/actions/entry-delete.svg + application/scalable/actions/entry-expire.svg application/scalable/actions/entry-restore.svg application/scalable/actions/entry-edit.svg application/scalable/actions/entry-new.svg @@ -55,6 +58,9 @@ application/scalable/actions/hibp.svg application/scalable/actions/lock-question.svg application/scalable/actions/keyboard-shortcuts.svg + application/scalable/actions/lock.svg + application/scalable/actions/lock-open.svg + application/scalable/actions/lock-open-alert.svg application/scalable/actions/message-close.svg application/scalable/actions/move-down.svg application/scalable/actions/move-up.svg @@ -67,8 +73,10 @@ application/scalable/actions/password-generator.svg application/scalable/actions/password-show-off.svg application/scalable/actions/password-show-on.svg + application/scalable/actions/proton.svg application/scalable/actions/qrcode.svg application/scalable/actions/refresh.svg + application/scalable/actions/remote-sync.svg application/scalable/actions/reports.svg application/scalable/actions/reports-exclude.svg application/scalable/actions/sort-alphabetical-ascending.svg @@ -84,6 +92,7 @@ application/scalable/actions/totp-copy.svg application/scalable/actions/totp-copy-password.svg application/scalable/actions/totp-edit.svg + application/scalable/actions/totp-invalid.svg application/scalable/actions/trash.svg application/scalable/actions/url-copy.svg application/scalable/actions/user-guide.svg diff --git a/share/linux/org.keepassxc.KeePassXC.appdata.xml b/share/linux/org.keepassxc.KeePassXC.appdata.xml index 16f50635a..a38728f5e 100644 --- a/share/linux/org.keepassxc.KeePassXC.appdata.xml +++ b/share/linux/org.keepassxc.KeePassXC.appdata.xml @@ -52,6 +52,104 @@ + + +
    +
  • Placeholder for future release notes
  • +
+
+
+ + +
    +
  • Allow adjusting application font size [#11567]
  • +
  • Add Proton Pass importer [#11197]
  • +
  • Support KeePass2 TOTP settings [#11229]
  • +
  • Add New/Preview Entry Attachments dialog and functionality [#11637, #11699, #11650]
  • +
  • Add database name, color, and icon options for unlock view [#10819, #11725]
  • +
  • Show entry background color as column [#6798]
  • +
  • Use icons for password strength [#9844]
  • +
  • Add "Group Full Path" column in entry view [#10278]
  • +
  • Passphrase "MIXED case" Type [#11255]
  • +
  • Allow deleting extension plugin data from Browser Statistics [#11218]
  • +
  • Add --minimized option to keepassxc [#11693]
  • +
  • Implement T-CONV and T-REPLACE-RX entry placeholders [#11453]
  • +
  • Option to disable opening browser when URL field double-clicked [#11332]
  • +
  • Overhaul action states and add icons to toolbar [#11047]
  • +
  • Show character count in password generator dialog [#10940]
  • +
  • Add ability to expire entries from context menu [#8731]
  • +
  • Add copy field shortcuts to Auto-Type select dialog [#11518]
  • +
  • Passkeys: Add support for selecting group on creation [#11260]
  • +
  • Browser: Refactor Access Control Dialog [#9607]
  • +
  • Browser: Add support for URL wildcards and exact URL [#9835, #11752]
  • +
  • Browser: Allow groups to restrict by browser integration key [#9852]
  • +
  • CLI: Add `-d` dry-run shortcut to merge command [#11192]
  • +
  • CLI: HTML export [#11590]
  • +
  • macOS: Add option to disable database lock when switching user [#9707]
  • +
  • SSH Agent: Implement feature to clear all identities [#10649]
  • +
  • Major enhancements to documentation [#11745, #10875]
  • +
  • Various UI and style fixes [#11535, #11672, #11511, #11445, #11426, #11273, #11455, #11321, #11594, #11539, #11351, #11354, #10748, #11602, #11303, #11291, #10091, #9417]
  • +
  • Various improvements to tags [#11676, #11652, #11625]
  • +
  • Reset splitter sizes on database unlock [#11014]
  • +
  • Remember sort order in Auto-type popup dialog [#9508]
  • +
  • Fix database password clearing when modifying key file / hardware key [#11001]
  • +
  • Fix issues with reloading and handling of externally modified db file [#10612]
  • +
  • Support passkeys with Bitwarden import [#11401]
  • +
  • Fix various quirks with CSV import [#11787]
  • +
  • Show Auto-Type select dialog even if window title is empty [#11603]
  • +
  • Refactor hardware key code to avoid deadlock [#11703, #10872]
  • +
  • Show a clear error if hardware key is found slots are not configured [#11609]
  • +
  • Fix signal/slot disconnect when opening import wizard [#11039]
  • +
  • Fix setting window title as modified [#11542]
  • +
  • Fix assert hit when viewing entry history [#11413]
  • +
  • Fix multiple crashes on Linux [#11513]
  • +
  • Fix backup file path time substitution [#10834]
  • +
  • Prevent long-running threads from deadlocking the program with only 1 CPU [#11155]
  • +
  • Hide the menubar when menus lose focus (if toggled off) [#11355, #11605]
  • +
  • CLI: Restore the original codepage on windows [#11470]
  • +
  • Passkeys: Various fixes [#10934, #10951]
  • +
  • Browser: Fix cancel with database unlock dialog [#11435]
  • +
  • Browser: Resolve references in Access Confirm dialog [#11055]
  • +
  • SSH Agent: Add timeout to streams to prevent deadlock [#11290]
  • +
  • macOS: Replace legacy code for screen recording permissions [#11428]
  • +
  • macOS: Implement Secure Input Mode [#11623]
  • +
  • macOS: Fix showing ambigious name in settings [#11373]
  • +
  • macOS: Fix copy-to-clipboard shortcut in entry preview widget [#10966]
  • +
  • Linux: Prevent multiple lock requests [#11306]
  • +
  • Snap: Prevent need for snap helper script to configure browser extension [#10924]
  • +
  • Windows: Detect outdated VC Redist with MSI installer [#11469]
  • +
  • Windows: Additional exclusion fields for clipboard [#11521]
  • +
+
+
+ + +
    +
  • Passkeys: Ability to easily remove a passkey from an entry [#10777]
  • +
  • Snap: Use new desktop portal for native messaging integration [#10906]
  • +
  • Improve entry placeholder/reference feature [#10846]
  • +
  • Improve CSV importing when title field isn't specified [#10843]
  • +
  • Improve encrypted Bitwarden importing [#10800]
  • +
  • Improve database settings UX [#10821]
  • +
  • Improve handling of clipboard actions from entry preview [#10810]
  • +
  • Improve group/entry view resize behavior and set sensible defaults [#10641]
  • +
  • Passkeys: Fix incorrect username fill [#10874]
  • +
  • Passkeys: Return additional data to the extension [#10857]
  • +
  • Fix password clear timer inconsistency on unlock view [#10708]
  • +
  • Fix portability check [#10760]
  • +
  • Fix page overflow on HTML exports [#10735]
  • +
  • Fix broken builds when using system provided zxcvbn [#10717]
  • +
  • Fix copy password button when text is selected [#10853]
  • +
  • Fix tab ordering on application settings pages [#10907]
  • +
  • SSH Agent: Fix broken decrypt button [#10638]
  • +
  • Windows: Fix ALT Auto-Type modifier [#10795]
  • +
  • Windows: Fix wrong DACL memory size allocation [#10712]
  • +
  • macOS: Fix monospace font sizing [#10739]
  • +
  • Flatpak: Fix configuration settings off-by-one error [#10688]
  • +
  • BSD: Fix compiling with libusb implementation [#10736]
  • +
+
+
    @@ -194,7 +292,7 @@
  • Browser: Revert code causing connection problems [#8665]
  • Browser: Fix socket file symbolic link on Linux [#8656]
  • Flatpak: Fix launching browser proxy service [#8680]
  • -
  • SSH Agent: Fix paegent support on Windows [#8619]
  • +
  • SSH Agent: Fix pageant support on Windows [#8619]
@@ -1064,7 +1162,7 @@
  • Compare window title to entry URLs [#556]
  • Implemented inline error messages [#162]
  • Ignore group expansion and other minor changes when making database "dirty" [#464]
  • -
  • Updated license and copyright information on souce files [#632]
  • +
  • Updated license and copyright information on source files [#632]
  • Added contributors list to about dialog [#629]
  • diff --git a/share/linux/org.keepassxc.KeePassXC.desktop.in b/share/linux/org.keepassxc.KeePassXC.desktop.in index bf633727a..c022b03f4 100644 --- a/share/linux/org.keepassxc.KeePassXC.desktop.in +++ b/share/linux/org.keepassxc.KeePassXC.desktop.in @@ -47,3 +47,5 @@ Categories=Utility;Security;Qt; MimeType=application/x-keepass2; SingleMainWindow=true X-GNOME-SingleWindow=true +Keywords=security;privacy;password-manager;yubikey;password;keepass; +Keywords[de]=sicherheit;privatsphäre;passwort-manager;yubikey;passwort;keepass; diff --git a/share/linux/org.keepassxc.KeePassXC.policy.in b/share/linux/org.keepassxc.KeePassXC.policy.in new file mode 100644 index 000000000..e5b837e0c --- /dev/null +++ b/share/linux/org.keepassxc.KeePassXC.policy.in @@ -0,0 +1,18 @@ + + + + KeePassXC Developers + + @APP_ICON_NAME@ + + + Quick Unlock for a KeePassXC Database + Authentication is required to unlock a KeePassXC Database + + no + auth_self + + + diff --git a/share/macosx/keepassxc.iconset/icon_128x128.png b/share/macosx/keepassxc.iconset/icon_128x128.png old mode 100755 new mode 100644 diff --git a/share/macosx/keepassxc.iconset/icon_128x128@2x.png b/share/macosx/keepassxc.iconset/icon_128x128@2x.png old mode 100755 new mode 100644 diff --git a/share/macosx/keepassxc.iconset/icon_16x16.png b/share/macosx/keepassxc.iconset/icon_16x16.png old mode 100755 new mode 100644 diff --git a/share/macosx/keepassxc.iconset/icon_16x16@2x.png b/share/macosx/keepassxc.iconset/icon_16x16@2x.png old mode 100755 new mode 100644 diff --git a/share/macosx/keepassxc.iconset/icon_256x256.png b/share/macosx/keepassxc.iconset/icon_256x256.png old mode 100755 new mode 100644 diff --git a/share/macosx/keepassxc.iconset/icon_256x256@2x.png b/share/macosx/keepassxc.iconset/icon_256x256@2x.png old mode 100755 new mode 100644 diff --git a/share/macosx/keepassxc.iconset/icon_32x32.png b/share/macosx/keepassxc.iconset/icon_32x32.png old mode 100755 new mode 100644 diff --git a/share/macosx/keepassxc.iconset/icon_32x32@2x.png b/share/macosx/keepassxc.iconset/icon_32x32@2x.png old mode 100755 new mode 100644 diff --git a/share/macosx/keepassxc.iconset/icon_512x512.png b/share/macosx/keepassxc.iconset/icon_512x512.png old mode 100755 new mode 100644 diff --git a/share/macosx/keepassxc.iconset/icon_512x512@2x.png b/share/macosx/keepassxc.iconset/icon_512x512@2x.png old mode 100755 new mode 100644 diff --git a/share/translations/keepassxc_ar.ts b/share/translations/keepassxc_ar.ts index a4fa386c9..741ca960c 100644 --- a/share/translations/keepassxc_ar.ts +++ b/share/translations/keepassxc_ar.ts @@ -3,11 +3,11 @@ AboutDialog About KeePassXC - حَول KeePassXC + حول KeePassXC About - حَول + حول Report bugs at: <a href="https://github.com/keepassxreboot/keepassxc/issues" style="text-decoration: underline;">https://github.com</a> @@ -217,18 +217,50 @@ You must restart the application to set the new language. Would you like to restart now? يجب إعادة تشغيل التطبيق لتعيين اللغة الجديدة. هل تريد إعادة التشغيل الآن ؟ - - Reset Settings? - إعادة تعيّين الإعدادات؟ - - - Are you sure you want to reset all general and security settings to default? - هل أنت متأكد من رغبتك في إعادة تعيّين كافة الإعدادات العامة وإعدادات الأمن إلى وضعها الافتراضي؟ - Select backup storage directory اختر مجلد النسخ الاحتياطي + + Confirm Reset + أكّد إعادة التعيين + + + Are you sure you want to reset all settings to default? + هل أنت متأكد أنك تريد إعادة تعيين كافة الإعدادات إلى الوضع الافتراضي؟ + + + Import KeePassXC Settings + استورد إعدادات KeePassXC + + + Failed to import settings from %1, not a valid settings file. + فشل استيراد الإعدادات من %1، ملف إعدادات غير صالح. + + + Export KeePassXC Settings + صدّر إعدادات KeePassXC + + + Small + + + + Normal + + + + Medium + + + + Large + + + + Custom + + ApplicationSettingsWidgetGeneral @@ -280,25 +312,6 @@ Include beta releases when checking for updates ضمّن النسخ التجريبية عند البحث عن التحديثات - - On database unlock, show entries that - عند إلغاء قفل قاعدة البيانات، أظهر الإدخالات التي - - - have expired - On database unlock, show entries that... - انتهت الصلاحية - - - days - On database unlock, show entries that will expire within %1 days - لأيام - - - will expire within - On database unlock, show entries that... - ستنتهي صلاحيتها في غضون - File Management إدارة الملفات @@ -323,22 +336,10 @@ Backup database file before saving إحتفظ بنسخة من ملف قاعدة البيانات قبل الحفظ - - Backup destination - وجهة الدعم الاحتياطي - - - Specifies the database backup file location. Occurrences of "{DB_FILENAME}" are replaced with the filename of the saved database without extension. {TIME:<format>} is replaced with the backup time, see https://doc.qt.io/qt-5/qdatetime.html#toString. <format> defaults to format string "dd_MM_yyyy_hh-mm-ss". - تحديد موقع ملف النسخ الاحتياطي لقاعدة البيانات. يتم استبدال تكرارات "{DB_FILENAME}" باسم ملف قاعدة البيانات المحفوظة بدون امتداد. يتم استبدال {TIME:<format>} بوقت النسخ الاحتياطي، راجع https://doc.qt.io/qt-5/qdatetime.html#toString. <format> الإعدادات الافتراضية لتنسيق السلسلة "dd_MM_yyyy_hh-mm-ss".</format></format> - {DB_FILENAME}.old.kdbx {DB_FILENAME}.old.kdbx - - Choose... - - Use alternative saving method (may solve problems with Dropbox, Google Drive, GVFS, etc.) استخدم طريقة حفظ بديلة (قد تحل مشاكل Dropbox و Google Drive و GVFS وما إلى ذلك) @@ -506,6 +507,73 @@ Remember last typed entry for: + + On database unlock, show entries that will expire within + عند فتح قاعدة البيانات، اعرض الإدخالات التي ستنتهي صلاحيتها خلال + + + On database unlock, show entries that will expire within + عند فتح قاعدة البيانات، اعرض الإدخالات التي ستنتهي صلاحيتها خلال + + + days + number of days warning for password expiration + لأيام + + + Destination format: + تنسيق الوجهة: + + + <html><head/><body><p><span style=" font-weight:600;">{DB_FILENAME}</span> is replaced with the filename of the saved database without extension</p><p><span style=" font-weight:600;">{TIME:&lt;format&gt;}</span> is replaced with the specified time format (default: dd_MM_yyyy_hh-mm-ss)</p><p>See the User Guide for more details</p></body></html> + + + + Choose folder... + اختر المجلد... + + + + + Show confirmation before moving entries to recycle bin + أظهِر التأكيد قبل نقل الإدخالات إلى سلة المهملات + + + Copy data on double clicking field in entry view + انسخ البيانات عند النقر المزدوج على الحقل في عرض الإدخال + + + Show toolbar + أظهِر شريط الأدوات + + + Show the menu bar by pressing the Alt key + + + + Show menubar + أظهِر شريط القائمة + + + Import settings… + استورد الإعدادات… + + + Export settings… + إعدادات التصدير… + + + Open browser on double clicking URL field in entry view + افتح المتصفح عن طريق النقر المزدوج على حقل عنوان URL في عرض الإدخال + + + Font size: + + + + Font size selection + + ApplicationSettingsWidgetSecurity @@ -571,18 +639,6 @@ Hide passwords in the entry preview panel اخفي كلمات السر في لوحة إستعراض المدخلات - - Hide entry notes by default - إخفاء مُدخل الملاحظات إفتراضيًا - - - Move entries to recycle bin without confirmation - نقل الإدخالات إلى سلة المحذوفات دون تأكيد - - - Enable double click to copy the username/password entry columns - قم بتمكين النقر المزدوج لنسخ اسم المستخدم / كلمة المرور - Privacy الخصوصية @@ -595,6 +651,18 @@ Hide TOTP in the entry preview panel إخفاء TOTP في لوحة المعاينة + + Lock databases when switching user + اقفل قواعد البيانات عند تبديل المستخدم + + + Lock Options + خيارات القفل + + + Hide notes in the entry preview panel + اخفِ الملاحظات في لوحة معاينة الإدخال + AutoType @@ -643,20 +711,6 @@ Entry does not have attribute for PICKCHARS: %1 لا يحتوي الإدخال على سمة ل PICKCHARS: ٪1 - - Invalid conversion type: %1 - نوع التحويل غير صالح: ٪1 - - - Invalid conversion syntax: %1 - هيئة التحويل غير صالحة: ٪1 - - - Invalid regular expression syntax %1 -%2 - هيئة التعبير غير صالحة ٪1 -%2 - Invalid placeholder: %1 عنصر النيابة غير صالح: ٪1 @@ -716,7 +770,7 @@ Trying to send invalid keyboard symbol. - + محاولة إرسال رمز لوحة المفاتيح غير صالح. @@ -819,7 +873,7 @@ Ctrl+4 - Use Virtual Keyboard (Windows Only)</p> Undo - + تراجع @@ -840,7 +894,7 @@ Please select the correct database for saving credentials. KeePassXC - Select Database - + KeePassXC - تحديد قاعدة البيانات @@ -855,11 +909,11 @@ Please select the correct database for saving credentials. Authenticate - + استَوثِق Register new - + سجلّ جديد Register @@ -883,7 +937,7 @@ Please select the correct database for saving credentials. Add to existing entry - + أضِف إلى الإدخال الموجود Existing passkey found. @@ -963,11 +1017,11 @@ Do you want to delete the entry? KeePassXC - Update Entry - + KeePassXC - حدّث الإدخال KeePassXC - Delete entry - + KeePassXC - احذف الإدخال KeePassXC - New key association request @@ -1017,10 +1071,6 @@ Do you want to overwrite the passkey in %1 - %2? General العام - - Browsers installed as snaps are currently not supported. - المتصفحات المثبتة كsnaps غير مدعومة حاليا. - Enable integration for these browsers: تفعيل التكامل لهذه المتصفحات: @@ -1192,18 +1242,6 @@ Do you want to overwrite the passkey in %1 - %2? Custom extension ID هوية امتداد خاصة - - Due to Snap sandboxing, you must run a script to enable browser integration.<br />You can obtain this script from %1 - نظرا ل Snap sandboxing ، يجب عليك تشغيل برنامج نصي لتمكين تكامل المتصفح.<br />يمكنك الحصول على هذا البرنامج النصي من ٪1 - - - KeePassXC-Browser is needed for the browser integration to work. <br />Download it for %1 and %2 and %3. %4 - هناك حاجة إلى KeePassXC-Browser حتى يعمل تكامل المتصفح. <br />قم بتنزيله ل ٪1 و٪2 و٪3. %4 - - - Please see special instructions for browser extension use below - يرجى الاطلاع على التعليمات الخاصة لاستخدام ملحق المتصفح أدناه - Executable Files ملفات برامج @@ -1252,6 +1290,14 @@ Do you want to overwrite the passkey in %1 - %2? Allow using localhost with passkeys + + KeePassXC-Browser is needed for the browser integration to work. <br />Download it for %1 and %2 and %3. + يلزم وجود KeePassXC-Browser لكي يعمل تكامل المتصفح. <br />نزله لـ %1 و %2 و %3. + + + Browsers installed using Snap or Flatpak are not supported with exception to Firefox installed using Snap. + + CloneDialog @@ -1388,12 +1434,25 @@ Do you want to overwrite the passkey in %1 - %2? Failed to parse CSV file: %1 - + فشل تحليل ملف CSV: %1 Imported from CSV file: %1 مُستورد من CSV ملف: %1 + + No Title Selected + + + + No title column was selected, entries will be hard to tell apart. +Are you sure you want to import? + + + + Tags + وسوم + CsvParserModel @@ -1457,19 +1516,27 @@ Backup database located at %2 Recycle Bin سلة المهملات + + Database file read error. + + + + No file path was provided. + + DatabaseOpenDialog Unlock Database - KeePassXC - فتح قاعدة البيانات - KEEPASSXC + افتح قاعدة البيانات - KeePassXC DatabaseOpenWidget Unlock KeePassXC Database - فتح قاعدة بيانات KEEPASSXC + افتح قاعدة بيانات KeePassXC Enter Password: @@ -1497,7 +1564,7 @@ Backup database located at %2 Unlock Database - فتح قاعدة البيانات + افتح قاعدة البيانات Cancel @@ -1505,7 +1572,7 @@ Backup database located at %2 Unlock - فتح + افتح Please present or touch your YubiKey to continue… @@ -1595,54 +1662,63 @@ To prevent this error from appearing, you must go to "Database Settings / S Failed to authenticate with Quick Unlock: %1 - + فشل المصادقة مع Windows Hello: %1 Select Key File: - + حدّد ملف المفتاح: <p>In addition to a password, you can use a secret file to enhance the security of your database. This file can be generated in your database's security settings.</p><p>This is <strong>not</strong> your *.kdbx database file!</p> - - - - Click to add a key file. - - - - <a href="#" style="text-decoration: underline">I have a key file</a> - + <p>بالإضافة إلى كلمة المرور، يمكنك استخدام ملف سري لتعزيز أمان قاعدة بياناتك. يمكن توليد هذا الملف في إعدادات أمان قاعدة بياناتك.</p><p>هذا <strong>ليس</strong> ملف قاعدة بيانات *.kdbx الخاص بك! Use hardware key [Serial: %1] - + استخدم مفتاح حماية عتادي [الرقم التسلسلي: %1] Use hardware key - + استخدم مفتاح الأجهزة Your database file is NOT a key file! If you don't have a key file or don't know what that is, you don't have to select one. - + ملف قاعدة البيانات الخاص بك ليس key file! +إذا لم يكن لديك ملف مفتاح أو لا تعرف ما هو، فلا داعي لتحديد واحد. KeePassXC database file selected - + حدّدت ملف قاعدة بيانات KeePassXC The file you selected looks like a database file. A database file is NOT a key file! Are you sure you want to continue with this file?. - + يبدو أن الملف الذي حددته هو ملف قاعدة بيانات. + +ملف قاعدة البيانات ليس key file! + +هل أنت متأكد من أنك تريد الاستمرار بهذا الملف؟ No hardware keys found. - + لم يتم العثور على مفتاح حماية عتادي. Refresh Hardware Keys + أنعش مفاتيح الحماية العتادي + + + Click to add a key file. + انقر لإضافة ملف مفتاح. + + + <a href="#" style="text-decoration: underline">I have a key file</a> + <a href="#" style="text-decoration: underline">لدي ملف مفتاح</a> + + + Hardware keys found, but no slots are configured. @@ -1679,6 +1755,22 @@ Are you sure you want to continue with this file?. Maintenance صيانة + + KeeShare + KeeShare + + + Secret Service Integration + + + + Remote Sync + + + + Database Settings: %1 + + DatabaseSettingsWidgetBrowser @@ -1792,7 +1884,7 @@ This is only necessary if your database is a copy of another and the browser ext No keys found - + لم يتم العثور على مفاتيح Removed keys from database @@ -1847,15 +1939,15 @@ Are you sure you want to continue without a password? Weak password - - - - You must enter a stronger password to protect your database. - + كلمة المرور ضعيفة This is a weak password! For better protection of your secrets, you should choose a stronger password. - + هذه كلمة مرور ضعيفة! لحماية أسرارك بشكل أفضل، يجب عليك اختيار كلمة مرور أقوى. + + + The provided password does not meet the minimum quality requirement. + كلمة المرور المقدمة لا تلبي الحد الأدنى من متطلبات الجودة. @@ -1998,11 +2090,11 @@ If you keep this number, your database will not be protected from brute force at Encryption Settings: - + إعدادات التعمية Basic - + أساسي Advanced @@ -2158,6 +2250,50 @@ removed from the database. Autosave delay since last change checkbox + + Public Database Metadata + بيانات الوصفية لقاعدة البيانات العامة + + + Warning: the following settings are not encrypted. + تحذير: الإعدادات التالية غير مُعمَّاة. + + + Display name: + اسم العرض: + + + Publically visible display name used on the unlock dialog + اسم العرض المرئي للعامة المستخدم في مربع حوار إلغاء القفل + + + Database public display name + اسم العرض العام لقاعدة البيانات + + + Display color: + لون العرض: + + + Publically visible color used on the unlock dialog + + + + Database public display color chooser + أداة اختيار لون العرض العام لقاعدة البيانات + + + Clear + مسح + + + Display icon: + أيقونة العرض: + + + Select Database Icon + حدد أيقونة قاعدة البيانات + DatabaseSettingsWidgetKeeShare @@ -2253,6 +2389,129 @@ removed from the database. حقل الوصف في قاعدة البيانات + + DatabaseSettingsWidgetRemote + + Sync Commands + + + + Remove + إزالة + + + Command Settings + + + + Name + الاسم + + + Save + احفظ + + + Download + نزل + + + Command: + + + + Download command field + + + + e.g.: "sftp user@hostname" or "scp user@hostname:DatabaseOnRemote.kdbx {TEMP_DATABASE}" + + + + Input: + + + + Download input field + + + + Upload + ارفع + + + Upload command field + + + + e.g.: "sftp user@hostname" or "scp {TEMP_DATABASE} user@hostname:DatabaseOnRemote.kdbx" + + + + Upload input field + + + + Name cannot be empty. + + + + Test + + + + Download command cannot be empty. + + + + Download failed with error: %1 + + + + Download finished, but file %1 could not be found. + + + + Download successful. + + + + Save Remote Settings + + + + You have unsaved changes. Do you want to save them? + + + + e.g.: +get DatabaseOnRemote.kdbx {TEMP_DATABASE} +exit +--- +{TEMP_DATABASE} is used as placeholder to store the database in a temporary location +The command has to exit. In case of `sftp` as last command `exit` has to be sent + + + + + e.g.: +put {TEMP_DATABASE} DatabaseOnRemote.kdbx +exit +--- +{TEMP_DATABASE} is used as placeholder to store the database in a temporary location +The command has to exit. In case of `sftp` as last command `exit` has to be sent + + + + + Timeout: + + + + seconds + ثواني + + DatabaseTabWidget @@ -2326,6 +2585,11 @@ This is definitely a bug, please report it to the developers. Database tab name modifier %1 [Locked] + + %1 [Temporary] + Database tab name modifier + + DatabaseWidget @@ -2449,26 +2713,6 @@ Save changes? File has changed الملف تغير - - The database file has changed. Do you want to load the changes? - قاعدة البيانات تغيرت. هل تريد تحميل التغييرات؟ - - - Merge Request - دمج الطلب - - - The database file has changed and you have unsaved changes. -Do you want to merge your changes? - تم تغيير ملف قاعدة البيانات ولديك تغييرات لم يتم حفظها. -هل تريد دمج التغييرات؟ - - - Could not open the new database file while attempting to autoreload. -Error: %1 - تعذر فتح ملف قاعدة البيانات الجديد أثناء محاولة التحميل التلقائي. -الخطأ: %1 - Disable safe saves? هل تريد تعطيل الحفظ الآمن؟ @@ -2520,6 +2764,86 @@ Disable safe saves and try again? Database tab name modifier %1 [قاعدة بيانات جديدة] + + Remote Sync did not contain any download or upload commands. + + + + Remote sync '%1' completed successfully! + + + + Remote sync '%1' failed: %2 + + + + Error while saving database %1: %2 + + + + Downloading... + + + + Uploading... + + + + Syncing... + + + + Remove passkey from entry + أزِل passkey من الإدخال + + + Do you want to remove the passkey from this entry? + + + + The database file "%1" was modified externally + + + + Do you want to load the changes? + + + + Reload database + + + + Reloading database… + + + + Reload canceled + + + + Reload successful + + + + Reload pending user action… + + + + The database file "%1" was modified externally.<br>How would you like to proceed?<br><br>Merge all changes<br>Ignore the changes on disk until save<br>Discard unsaved changes + + + + The database file "%1" was modified externally.<br>How would you like to proceed?<br><br>Merge all changes then save<br>Overwrite the changes on disk<br>Discard unsaved changes + + + + Database file overwritten. + + + + Database file on disk cannot be unlocked with current credentials.<br>Enter new credentials and/or present hardware key to continue. + + EditEntryWidget @@ -2571,10 +2895,6 @@ Disable safe saves and try again? n/a n/a - - (encrypted) - (مُعمّى) - Select private key إختر المفتاح السري @@ -2677,6 +2997,10 @@ Would you like to correct it? %n year(s) ٪n سنةسنةسنتين٪n سنوات٪n سنة٪n سنة + + Failed to decrypt SSH key, ensure password is correct. + فشل فك تعمية مفتاح SSH، تأكد من صحة كلمة المرور. + EditEntryWidgetAdvanced @@ -2848,18 +3172,10 @@ Would you like to correct it? Skip Auto-Submit for this entry تخطي الإرسال التلقائي لهذا الإدخال - - Only send this setting to the browser for HTTP Auth dialogs. If enabled, normal login forms will not show this entry for selection. - أرسل هذا الإعداد إلى المتصفح فقط لمربع حوار مصادقة HTTP. في حالة التفعيل ، لن تعرض نماذج تسجيل الدخول العادية هذا المٌدخل للاختيار. - Use this entry only with HTTP Basic Auth استخدم هذا الإدخال فقط مع مصادقة HTTP البدائية - - Do not send this setting to the browser for HTTP Auth dialogs. If enabled, HTTP Auth dialogs will not show this entry for selection. - لا ترسل هذا الإعداد إلى المتصفح لمربعات حوار مصادقة HTTP. في حالة التمكين، لن تعرض مربعات حوار مصادقة HTTP هذا المُدخل للاختيار. - Do not use this entry with HTTP Basic Auth لا تستخدم هذا الإدخال مع مصادقة HTTP البدائية @@ -2882,6 +3198,14 @@ Would you like to correct it? Additional URLs + عناوين URL الإضافية + + + Only send this entry to the browser for HTTP Auth dialogs. If enabled, normal login forms will not show this entry for selection. + + + + Do not send this entry to the browser for HTTP Auth dialogs. If enabled, HTTP Auth dialogs will not show this entry for selection. @@ -3106,6 +3430,10 @@ Would you like to correct it? seconds ثواني + + Clear agent + + EditGroupWidget @@ -3470,7 +3798,7 @@ Supported extensions are: %1. You can enable the DuckDuckGo website icon service under Application Settings -> Security - + يمكنك تفعيل خدمة أيقونة موقع DuckDuckGo ضمن إعدادات التطبيق -> الأمان @@ -3548,6 +3876,24 @@ This may cause the affected plugins to malfunction. %1 - Clone %1 - استنساخ + + Passkey + + + + Invalid conversion type: %1 + نوع تحويل غير صالح: %1 + + + Invalid conversion syntax: %1 + هيئة التحويل غير صالحة: %1 + + + Invalid regular expression syntax %1 +%2 + هيئة التعبير غير صالحة %1 +%2 + EntryAttachments @@ -3556,6 +3902,21 @@ This may cause the affected plugins to malfunction. لا يمكن فتح الملف "%1" + + EntryAttachmentsDialog + + Form + النموذج + + + File name + + + + File contents... + + + EntryAttachmentsModel @@ -3593,14 +3954,6 @@ This may cause the affected plugins to malfunction. Remove إزالة - - Rename selected attachment - إعادة تسمية المرفق المحدد - - - Rename - اعادة تسمية - Open selected attachment فتح المرفق المحدد @@ -3720,6 +4073,18 @@ Would you like to overwrite the existing attachment? المرفق "%1" موجود بالفعل. هل ترغب في الكتابة فوق المرفق الموجود؟ + + New + + + + Preview + معاينة + + + Failed to preview an attachment: Attachment not found + فشل معاينة المرفق: لم يتم العثور على المرفق + EntryAttributesModel @@ -3918,6 +4283,10 @@ Would you like to overwrite the existing attachment? Background Color + + Group Path + + EntryPreviewWidget @@ -4279,7 +4648,7 @@ You can enable the DuckDuckGo website icon service in the security section of th ImportWizard Import Wizard - + استورد المساعد @@ -4312,6 +4681,14 @@ You can enable the DuckDuckGo website icon service in the security section of th Url عنوان Url + + Could not load key file. + + + + Could not open remote database. Password or key file may be incorrect. + + ImportWizardPageSelect @@ -4321,7 +4698,7 @@ You can enable the DuckDuckGo website icon service in the security section of th Import File Selection - + استيراد اختيار الملف Password: @@ -4345,7 +4722,7 @@ You can enable the DuckDuckGo website icon service in the security section of th No unlocked databases available - + لا تتوفر قواعد بيانات مفتوحة Existing Database: @@ -4361,11 +4738,11 @@ You can enable the DuckDuckGo website icon service in the security section of th 1Password Export (.1pux) - + تصدير 1Password (.1pux) 1Password Vault (.opvault) - + 1Password مخزن (.opvault) Bitwarden (.json) @@ -4381,7 +4758,7 @@ You can enable the DuckDuckGo website icon service in the security section of th Select import file - + حدد ملف الاستيراد All files @@ -4401,20 +4778,58 @@ You can enable the DuckDuckGo website icon service in the security section of th 1Password Export - + صدّر 1Password Bitwarden JSON Export - + تصدير JSON من Bitwarden 1Password Vault - + مخزن 1Password KeePass1 Database + + Proton Pass (.json) + + + + Proton Pass JSON Export + تصدير JSON إلى Proton Pass + + + Temporary Database + + + + Command: + + + + e.g.: "sftp user@hostname" or "scp user@hostname:DatabaseOnRemote.kdbx {TEMP_DATABASE}" + + + + Input: + + + + e.g.: +get DatabaseOnRemote.kdbx {TEMP_DATABASE} +exit +--- +{TEMP_DATABASE} is used as placeholder to store the database in a temporary location +The command has to exit. In case of `sftp` as last commend `exit` has to be sent + + + + + Remote Database (.kdbx) + + KMessageWidget @@ -4689,7 +5104,11 @@ If this reoccurs, then your database file may be corrupt. You can import it by clicking on Database > 'Import KeePass 1 database…'. This is a one-way migration. You won't be able to open the imported database with the old KeePassX 0.4 version. - + الملف المحدد عبارة عن قاعدة بيانات KeePass 1 قديمة (.kdb). + +يمكنك استيرادها بالنقر فوق قاعدة البيانات > "استيراد قاعدة بيانات KeePass 1…'. + +هذه عملية انتقال في اتجاه واحد. لن تتمكن من فتح قاعدة البيانات المستوردة باستخدام إصدار KeePassX 0.4 القديم. Not a KeePass database. @@ -4826,7 +5245,7 @@ Line %2, column %3 KeeAgentSettings Invalid KeeAgent settings file structure. - + بنية ملف إعدادات KeeAgent غير صالحة. Private key is an attachment but no attachments provided. @@ -5101,7 +5520,7 @@ If this reoccurs, then your database file may be corrupt. You selected a key file in an old format which KeePassXC<br>may stop supporting in the future.<br><br>Please consider generating a new key file instead. - + لقد قمت بتحديد ملف مفتاح بتنسيق قديم قد يتوقف KeePassXC<br> عن دعمه في المستقبل.<br><br>يُرجى التفكير في إنشاء ملف مفتاح جديد بدلاً من ذلك. Error loading the key file '%1' @@ -5163,7 +5582,7 @@ Message: %2 You cannot use the current database as its own keyfile. Please choose a different file or generate a new key file. - + لا يمكنك استخدام قاعدة البيانات الحالية كkeyfile خاص بها. يُرجى اختيار ملف مختلف أو إنشاء ملف مفتاح جديد. Suspicious Key File @@ -5172,7 +5591,8 @@ Message: %2 The chosen key file looks like a password database file. A key file must be a static file that never changes or you will lose access to your database forever. Are you sure you want to continue with this file? - + يبدو ملف المفتاح المختار كملف قاعدة بيانات كلمة المرور. يجب أن يكون ملف المفتاح ملفًا ثابتًا لا يتغير أبدًا وإلا ستفقد الوصول إلى قاعدة بياناتك إلى الأبد. +هل أنت متأكد أنك تريد الاستمرار في هذا الملف؟ @@ -5318,7 +5738,7 @@ Are you sure you want to continue with this file? Database &Reports… - + قاعدة البيانات والتقارير… &Database Settings… @@ -5390,7 +5810,7 @@ Are you sure you want to continue with this file? &HTML File… - + ملف &HTML… KeePass 1 Database… @@ -5398,7 +5818,7 @@ Are you sure you want to continue with this file? 1Password Vault… - + مخزن 1Password… CSV File… @@ -5466,11 +5886,11 @@ Are you sure you want to continue with this file? Add key to SSH Agent - + أضِف مفتاح إلى عميل SSH Remove key from SSH Agent - + أزِل المفتاح من SSH Agent Compact Mode @@ -5494,7 +5914,7 @@ Are you sure you want to continue with this file? Show Menubar - + أظهِر شريط القائمة Show Toolbar @@ -5540,25 +5960,22 @@ Are you sure you want to continue with this file? WARNING: You are using an unstable build of KeePassXC. There is a high risk of corruption, maintain a backup of your databases. This version is not meant for production use. - + تحذير: أنت تستخدم إصدارًا غير مستقر من KeePassXC. +هناك خطر كبير للفساد، احتفظ بنسخة احتياطية من قواعد بياناتك. +هذا الإصدار ليس مخصصًا للاستخدام الإنتاجي. NOTE: You are using a pre-release version of KeePassXC. Expect some bugs and minor issues, this version is meant for testing purposes. - - WARNING: Your Qt version may cause KeePassXC to crash with an On-Screen Keyboard. -We recommend you use the AppImage available on our downloads page. - - No Tags لا وسوم Restore Entry(s) - + استعد الإدخالاتاستعد الإدخالاتاستعد الإدخالاتاستعد الإدخالاتاستعد الإدخالاتاستعد الإدخالات Settings @@ -5566,15 +5983,15 @@ We recommend you use the AppImage available on our downloads page. Check for updates on startup? - + التحقق من وجود تحديثات عند بدء التشغيل؟ Would you like KeePassXC to check for updates on startup? - + هل ترغب في أن يقوم KeePassXC بالتحقق من التحديثات عند بدء التشغيل؟ You can always check for updates manually from the application menu. - + يمكنك دائمًا التحقق من التحديثات يدويًا من قائمة التطبيق. Toggle window @@ -5606,15 +6023,15 @@ We recommend you use the AppImage available on our downloads page. 1Password 1PUX... - + 1Password 1PUX... Import a 1Password 1PUX file - + استورد ملف 1Password 1PUX Import… - + استورد… Passkeys… @@ -5625,16 +6042,20 @@ We recommend you use the AppImage available on our downloads page. استورِد Passkey - Quit Application + Remote S&ync… + + Quit Application + أنهِ التطبيق + Open About Dialog Open Database - + افتح قاعدة بيانات Create Database @@ -5728,6 +6149,10 @@ We recommend you use the AppImage available on our downloads page. Show Password Generator + + Remove Passkey From Entry + + Perform Auto-Type: {USERNAME} @@ -5790,7 +6215,7 @@ We recommend you use the AppImage available on our downloads page. Empty Recycle Bin - + إفراغ سلة المهملات Open Donation Website @@ -5842,7 +6267,7 @@ We recommend you use the AppImage available on our downloads page. Toggle Show Menubar - + بدّل إظهار شريط القائمة Toggle Show Toolbar @@ -5872,6 +6297,34 @@ We recommend you use the AppImage available on our downloads page. Toggle Allow Screen Capture + + Show Group Panel + + + + Toggle Show Group Panel + + + + Setup Remote Sync… + + + + Password Generator + مولد كلمة السر + + + E&xpire Entry… + + + + Clear SSH Agent + + + + Clear all identities in ssh-agent + + ManageDatabase @@ -5889,7 +6342,7 @@ We recommend you use the AppImage available on our downloads page. Unlock database to show more information - + افتح قاعدة البيانات لإظهار المزيد من المعلومات Lock database @@ -5908,11 +6361,11 @@ We recommend you use the AppImage available on our downloads page. Reset - + صفّر Reset any remembered decisions for this application - + صفّر أي قرارات تم تذكرها لهذا التطبيق @@ -5986,7 +6439,7 @@ We recommend you use the AppImage available on our downloads page. Here you can adjust the database encryption settings. Don't worry, you can change them later in the database settings. - + يمكنك هنا ضبط إعدادات تعمية قاعدة البيانات. لا تقلق، يمكنك تغييرها لاحقًا في إعدادات قاعدة البيانات. @@ -5997,7 +6450,7 @@ We recommend you use the AppImage available on our downloads page. A set of credentials known only to you that protects your database. - + مجموعة من بيانات الاعتماد المعروفة لك فقط والتي تحمي قاعدة البيانات الخاصة بك. @@ -6008,7 +6461,7 @@ We recommend you use the AppImage available on our downloads page. Here you can adjust the database encryption settings. Don't worry, you can change them later in the database settings. - + يمكنك هنا ضبط إعدادات تعمية قاعدة البيانات. لا تقلق، يمكنك تغييرها لاحقًا في إعدادات قاعدة البيانات. @@ -6019,6 +6472,25 @@ We recommend you use the AppImage available on our downloads page. Please fill in the display name and an optional description for your new database: + يُرجى ملء اسم العرض والوصف الاختياري لقاعدة البيانات الجديدة الخاصة بك: + + + + NewEntryAttachmentsDialog + + Attachment name cannot be empty + + + + Attachment with the same name already exists + + + + Save attachment + احفظ المرفق + + + New entry attachment @@ -6026,7 +6498,7 @@ We recommend you use the AppImage available on our downloads page. NixUtils Password Manager - + مدير كلمة المرور Global shortcut already registered to %1 @@ -6061,11 +6533,11 @@ We recommend you use the AppImage available on our downloads page. Unable to process clearText in place - + غير قادر على معالجة النص الواضح في مكانه Expected %1 bytes of clear-text, found %2 - + من المتوقع وجود %1 بايت من النص العادي، وتم العثور على %2 @@ -6209,6 +6681,10 @@ We recommend you use the AppImage available on our downloads page. Unexpected EOF when writing private key نهاية الملف غير معروفة عند قراءة المفتاح الخاص + + (encrypted) + (مُعمّى) + OpenSSHKeyGenDialog @@ -6233,7 +6709,7 @@ We recommend you use the AppImage available on our downloads page. PasskeyExportDialog KeePassXC - Passkey Export - + KeePassXC - تصدير Passkey Filenames will be generated with title and .passkey file extension. @@ -6241,11 +6717,11 @@ We recommend you use the AppImage available on our downloads page. Export entries - + تصدير الإدخالات Export Selected - + تصدير المحدد Cancel @@ -6253,18 +6729,18 @@ We recommend you use the AppImage available on our downloads page. Export to folder - + صدّر إلى مجلد Export the following passkey entries. - + تصدير إدخالات passkey التالية. PasskeyExporter KeePassXC: Passkey Export - + KeePassXC: تصدير Passkey File "%1.passkey" already exists. @@ -6274,15 +6750,15 @@ Do you want to overwrite it? Cannot open file - + لا يمكن فتح الملف Cannot open file "%1" for writing. - + لا يمكن فتح الملف "%1" للكتابة. Cannot write to file - + لا يمكن الكتابة إلى الملف @@ -6352,15 +6828,15 @@ Do you want to overwrite it? Cannot open file - + لا يمكن فتح الملف Cannot open file "%1" for reading. - + لا يمكن فتح الملف "%1" للقراءة. Open passkey file - + فتح ملف مفتاح المرور Cannot import passkey @@ -6393,11 +6869,11 @@ The following data is missing: Confirm password: - + تأكيد كلمة المرور: Repeat password field - + حقل تكرار كلمة المرور Password @@ -6405,7 +6881,7 @@ The following data is missing: Add Password - + أضِف كلمة المرور Change Password @@ -6421,11 +6897,11 @@ The following data is missing: <p>A password is the primary method for securing your database.</p><p>Good passwords are long and unique. KeePassXC can generate one for you.</p> - + <p>كلمة المرور هي الطريقة الأساسية لتأمين قاعدة بياناتك.</p><p>كلمات المرور الجيدة طويلة وفريدة من نوعها. يمكن لـ KeePassXC إنشاء واحد لك.</p> Passwords do not match. - + كلمة المرور غير مطابقة. @@ -6469,7 +6945,7 @@ The following data is missing: Password length - + طول كلمة المرور Switch to advanced mode @@ -6533,7 +7009,7 @@ The following data is missing: Additional characters - + أحرف إضافية Add non-hex letters to "do not include" list @@ -6541,7 +7017,7 @@ The following data is missing: Hex Passwords - + كلمات المرور السداسية Hex @@ -6559,10 +7035,6 @@ The following data is missing: Also choose from: اختر أيضا من: - - Excluded characters: "0", "1", "l", "I", "O", "|", "﹒" - استبعاد المِحرَفات: "0", "1", "l", "I", "O", "|", "﹒" - Exclude look-alike characters استبعاد الرموز التي تبدو على حد سواء @@ -6587,10 +7059,6 @@ The following data is missing: Word Count: عدد الكلمات: - - Character Count: - عدد المِحرَفات: - Word Case: حالة أحرف الكلمات: @@ -6603,10 +7071,6 @@ The following data is missing: Add custom wordlist إضافة قائمة كلمات مخصصة - - character - - Close إغلاق @@ -6617,7 +7081,7 @@ The following data is missing: Apply Password - + طبّق كلمة المرور Regenerate password (%1) @@ -6712,16 +7176,32 @@ Do you want to overwrite it? Special Characters محارف خاصة + + passwordLength + طول كلمة المرور + + + Characters: %1 + + + + MIXED case + + + + Excluded characters: "0", "1", "l", "I", "O", "|", "﹒", "B", "8", "G", "6" + + PasswordWidget Passwords do not match - + كلمة المرور غير مطابقة Passwords match so far - + كلمات المرور متطابقة حتى الآن Toggle Password (%1) @@ -6733,7 +7213,7 @@ Do you want to overwrite it? Warning: Caps Lock enabled! - + تحذير: Caps Lock مُفعّل! Quality: %1 @@ -6779,6 +7259,21 @@ Do you want to overwrite it? + + PreviewEntryAttachmentsDialog + + Preview entry attachment + معاينة إدخال المرفق + + + No preview available + لا يوجد معاينة متاحة + + + Image format not supported + + + QMessageBox @@ -6819,7 +7314,7 @@ Do you want to overwrite it? Continue with weak password - + تابع بكلمة مرور ضعيفة @@ -6846,7 +7341,7 @@ Do you want to overwrite it? Message encryption failed. - + فشل تعمية الرسالة. KeePassXC association failed, try again @@ -6982,7 +7477,7 @@ Do you want to overwrite it? Check if any passwords have been publicly leaked. FILENAME must be the path of a file listing SHA-1 hashes of leaked passwords in HIBP format, as available from https://haveibeenpwned.com/Passwords. - + تحقق مما إذا كان قد تم تسريب أي كلمات مرور علنًا. يجب أن يكون FILENAME هو مسار ملف يسرد تجزئات SHA-1 لكلمات المرور المسربة بتنسيق HIBP، كما هو متاح من https://haveibeenpwned.com/Passwords. FILENAME @@ -7111,7 +7606,7 @@ Do you want to overwrite it? Copy the current TOTP to the clipboard (equivalent to "-a totp"). - + انسخ TOTP الحالي إلى الحافظة (أي ما يعادل "-a totp"). Must match only one entry, otherwise a list of possible matches is shown. @@ -7152,7 +7647,7 @@ Do you want to overwrite it? Entry with path %1 has no TOTP set up. - + الإدخال ذو المسار %1 ليس له إعداد TOTP. ERROR: attribute %1 is ambiguous, it matches %2. @@ -7180,11 +7675,11 @@ Do you want to overwrite it? Display this help. - + عرض هذه المساعدة. Silence password prompt and other secondary outputs. - + إسكات كلمة المرور والمخرجات الثانوية الأخرى. Key file of the database. @@ -7196,7 +7691,7 @@ Do you want to overwrite it? Deactivate password key for the database. - + إلغاء تنشيط مفتاح كلمة المرور لقاعدة البيانات. Yubikey slot and optional serial used to access the database (e.g., 1:7370001). @@ -7220,7 +7715,7 @@ Do you want to overwrite it? Target decryption time in MS for the database. - + وقت فك التشفير المستهدف بالميجا بايت لقاعدة البيانات. time @@ -7232,7 +7727,7 @@ Do you want to overwrite it? Set a password for the database. - + عيّن كلمة مرور لقاعدة البيانات. Create a new database. @@ -7240,15 +7735,15 @@ Do you want to overwrite it? Invalid decryption time %1. - + وقت فك التعمية غير صالح ٪1. Target decryption time must be between %1 and %2. - + يجب أن يكون وقت فك التعمية المستهدف بين %1 و%2. Failed to set database password. - + فشل في تعيين كلمة مرور قاعدة البيانات. Loading the key file failed @@ -7268,7 +7763,7 @@ Do you want to overwrite it? error while setting database key derivation settings. - + خطأ أثناء تعيين إعدادات اشتقاق مفتاح قاعدة البيانات. File %1 already exists. @@ -7284,7 +7779,7 @@ Do you want to overwrite it? Unset the password for the database. - + ألغِ تعيين كلمة المرور لقاعدة البيانات. Unset the key file for the database. @@ -7360,11 +7855,11 @@ Do you want to overwrite it? Recycle bin is enabled. - + سلة المهملات مُفعّلة. Recycle bin is not enabled. - + سلة المهملات غير مُفعّلة. Location @@ -7388,7 +7883,7 @@ Do you want to overwrite it? no - + لا Number of groups @@ -7404,19 +7899,19 @@ Do you want to overwrite it? Unique passwords - + كلمات مرور فريدة Non-unique passwords - + كلمات مرور غير فريدة Maximum password reuse - + الحد الأقصى لإعادة استخدام كلمة المرور Number of short passwords - + عدد كلمات المرور القصيرة Number of weak passwords @@ -7424,11 +7919,11 @@ Do you want to overwrite it? Entries excluded from reports - + الإدخالات المستبعدة من التقارير Average password length - + متوسط ​​طول كلمة المرور %1 characters @@ -7457,10 +7952,6 @@ Do you want to overwrite it? Invalid word count %1 عدد كلمات غير صالح ٪1 - - The word list is too small (< 1000 items) - - Title for the entry. عنوان المُدخل @@ -7599,23 +8090,19 @@ Do you want to overwrite it? *** Password length (%1) != sum of length of parts (%2) *** - + *** طول كلمة المرور (%1) != مجموع طول الأجزاء (%2) *** Exit interactive mode. - - Format to use when exporting. Available choices are 'xml' or 'csv'. Defaults to 'xml'. - - Exports the content of a database to standard output in the specified format. - + يقوم بتصدير محتوى قاعدة البيانات إلى إخراج قياسي بالتنسيق المحدد. Unable to export database to XML: %1 - + غير قادر على تصدير قاعدة البيانات إلى XML: ‏%1 Unsupported format %1 @@ -7675,15 +8162,15 @@ Do you want to overwrite it? Invalid password length %1 - + طول كلمة المرور %1 غير صالح Invalid password generator after applying all options - + مولّد كلمة المرور غير صالح بعد تطبيق جميع الخيارات Display command help. - + عرض تعليمات الأمر. Available commands: @@ -7695,7 +8182,7 @@ Do you want to overwrite it? Path of the XML database export. - + مسار تصدير قاعدة بيانات XML. Path of the new database. @@ -7729,7 +8216,7 @@ Available commands: Displays debugging information. - + يعرض معلومات التصحيح. Invalid command %1. @@ -7765,7 +8252,7 @@ Available commands: Deactivate password key for the database to merge from. - + قم بإلغاء تنشيط مفتاح كلمة المرور لقاعدة البيانات المراد الدمج منها. Only print the changes detected by the merge operation. @@ -7790,7 +8277,8 @@ Available commands: Error reading merge file: %1 - + خطأ في قراءة ملف الدمج: +%1 Unable to save database to file : %1 @@ -7830,7 +8318,7 @@ Available commands: Open a database. - + افتح قاعدة البيانات. Path of the entry to remove. @@ -7874,7 +8362,7 @@ Available commands: Show the entry's current TOTP. - + أظهِر TOTP الحالي للمدخل. Show the protected attributes in clear text. @@ -7918,15 +8406,15 @@ Available commands: Failed to open database file %1: not found - + فشل فتح ملف قاعدة البيانات %1: غير موجود Failed to open database file %1: not a plain file - + فشل فتح ملف قاعدة البيانات %1: ليس ملفًا عاديًا Failed to open database file %1: not readable - + فشل فتح ملف قاعدة البيانات %1: غير قابل للقراءة Enter password to unlock %1: @@ -7941,7 +8429,10 @@ Available commands: stop supporting in the future. Please consider generating a new key file. - + تحذير: أنت تستخدم تنسيق ملف مفتاح قديم قد يتوقف KeePassXC +عن دعمة في المستقبل. + +يُرجى النظر في إنشاء ملف مفتاح جديد. Invalid YubiKey slot %1 @@ -7957,23 +8448,23 @@ Please consider generating a new key file. Enter password to encrypt database (optional): - + أدخل كلمة المرور لتعمية قاعدة البيانات (اختياري): Do you want to create a database with an empty password? [y/N]: - + هل تريد إنشاء قاعدة بيانات بكلمة مرور فارغة؟ [y/N]: Repeat password: - + اعِد كلمة المرور: Error: Passwords do not match. - + خطأ: كلمات المرور غير متطابقة. No program defined for clipboard manipulation - + لم يُعرّف أي برنامج لمعالجة الحافظة All clipping programs failed. Tried %1 @@ -7982,11 +8473,11 @@ Please consider generating a new key file. Creating KeyFile %1 failed: %2 - + فشل إنشاء KeyFile %1: %2 Loading KeyFile %1 failed: %2 - + فشل تحميل KeyFile %1: %2 HIBP file, line %1: parse error @@ -8002,7 +8493,7 @@ Please consider generating a new key file. Error: okon process did not finish - + خطأ: لم تنتهي عملية okon Failed to load okon processed database: %1 @@ -8010,15 +8501,15 @@ Please consider generating a new key file. Very weak password - + كلمة المرور ضعيفة جدًا Password entropy is %1 bits - + احتمال كلمة المرور هي %1 بت Weak password - + كلمة المرور ضعيفة Used in %1/%2 @@ -8026,7 +8517,7 @@ Please consider generating a new key file. Password is used %1 time(s) - + استخدُمت كلمة المرور %1 مرةاستخدُمت كلمة المرور مرةاستخدُمت كلمة المرور مرتاناستخدُمت كلمة المرور %1 مراتاستخدُمت كلمة المرور %1 مرةاستخدُمت كلمة المرور %1 مرة Password has expired @@ -8034,7 +8525,7 @@ Please consider generating a new key file. Password expiry was %1 - + انتهاء صلاحية كلمة المرور كان %1 Password expires on %1 @@ -8094,7 +8585,7 @@ Kernel: %3 %4 KeeShare - + KeeShare YubiKey @@ -8154,7 +8645,7 @@ Kernel: %3 %4 Argon2%1 (%2 rounds, %3 KB) - + Argon2%1 (%2 جولات، %3 ك.بايت) SymmetricCipher::init: Invalid cipher mode. @@ -8192,18 +8683,6 @@ Kernel: %3 %4 file empty ملف فارغ - - malformed string - سلسلة غير صحيحة - - - missing closing quote - إغلاق الإقتباس مفقود - - - %1: (row, col) %2,%3 - - AES 256-bit @@ -8218,11 +8697,11 @@ Kernel: %3 %4 Argon2d (KDBX 4 – recommended) - + Argon2d (KDBX 4 – موصى به) Argon2id (KDBX 4) - + Argon2id (KDBX 4) AES-KDF (KDBX 4) @@ -8304,15 +8783,15 @@ Kernel: %3 %4 Do you really want to move entry "%1" to the recycle bin? - + هل تريد حقًا نقل الإدخال "%1" إلى سلة المهملات؟ Do you really want to move %n entry(s) to the recycle bin? - + هل تريد حقًا نقل %n إدخالاً إلى سلة المهملات؟هل تريد حقًا نقل %n إدخالاً إلى سلة المهملات؟هل تريد حقًا نقل %n إدخالاً إلى سلة المهملات؟هل تريد حقًا نقل %n إدخالاً إلى سلة المهملات؟هل تريد حقًا نقل %n إدخالاً إلى سلة المهملات؟هل تريد حقًا نقل %n إدخالاً إلى سلة المهملات؟ Move entry(s) to recycle bin? - + انقل الإدخالات إلى سلة المهملات؟انقل الإدخال إلى سلة المهملات؟انقل الإدخالات إلى سلة المهملات؟انقل الإدخالات إلى سلة المهملات؟انقل الإدخالات إلى سلة المهملات؟انقل الإدخالات إلى سلة المهملات؟ Replace references to entry? @@ -8332,7 +8811,7 @@ Kernel: %3 %4 Health Check - + فحص الصحة HIBP @@ -8451,7 +8930,7 @@ This option is deprecated, use --set-key-file instead. Databases have been locked. - + لقد قُفلت قواعد البيانات. Attestation not supported @@ -8463,7 +8942,7 @@ This option is deprecated, use --set-key-file instead. Passkeys request canceled - + أُلغِيَ طلب Passkeys Invalid user verification @@ -8471,7 +8950,7 @@ This option is deprecated, use --set-key-file instead. Empty public key - + المفتاح العام فارغ Invalid URL provided @@ -8527,7 +9006,7 @@ This option is deprecated, use --set-key-file instead. Failed to encrypt key data. - + فشل في تعمية البيانات الرئيسية. Failed to get Windows Hello credential. @@ -8535,7 +9014,7 @@ This option is deprecated, use --set-key-file instead. Failed to decrypt key data. - + فشل فك تعمية البيانات الرئيسية. Origin is empty or not allowed @@ -8555,7 +9034,7 @@ This option is deprecated, use --set-key-file instead. Wait for timer to expire - + انتظر حتى انتهاء الوقت Challenge is shorter than required minimum length @@ -8568,7 +9047,7 @@ This option is deprecated, use --set-key-file instead. Favorite Tag for favorite entries - + المفضلة File does not exist. @@ -8576,7 +9055,7 @@ This option is deprecated, use --set-key-file instead. Cannot open file: %1 - + لا يمكن فتح الملف: %1 Cannot parse file: %1 at position %2 @@ -8584,7 +9063,7 @@ This option is deprecated, use --set-key-file instead. Failed to decrypt json file: %1 - + فشل فك تعمية ملف json: ‏%1 Invalid encKeyValidation field @@ -8596,15 +9075,15 @@ This option is deprecated, use --set-key-file instead. Wrong password - + كلمة مرور خاطئة Invalid encrypted data field - + حقل بيانات مُعمَّاة غير صالحة Invalid cipher list within encrypted data field - + قائمة تعمية غير صالحة ضمن حقل البيانات المُعمَّاة Cannot initialize cipher @@ -8612,16 +9091,16 @@ This option is deprecated, use --set-key-file instead. Cannot decrypt data - + لا يمكن فك تعمية البيانات Bitwarden Import - + استورد Bitwarden Archived Tag for archived entries - + مؤرشف Invalid 1PUX file format: Not a valid ZIP file. @@ -8629,11 +9108,11 @@ This option is deprecated, use --set-key-file instead. Invalid 1PUX file format: Missing export.data - + تنسيق ملف 1PUX غير صالح: بيانات التصدير مفقودة 1Password Import - + استورد 1Password Enter Shortcut @@ -8648,13 +9127,89 @@ This option is deprecated, use --set-key-file instead. - Unsupported KDF type, cannot decrypt json file + Unknown passkeys error - Unknown passkeys error + Invalid KDF iterations, cannot decrypt json file + تكرارات KDF غير صالحة، لا يمكن فك تشفير ملف json + + + Unsupported format, ensure your Bitwarden export is password-protected + التنسيق غير مدعوم، تأكد من أن تصدير Bitwarden الخاص بك محمي بكلمة مرور + + + Only PBKDF and Argon2 are supported, cannot decrypt json file + يتم دعم PBKDF وArgon2 فقط، ولا يمكن فك تعمية ملف json + + + Reset Shortcuts + + Double click an action to change its shortcut + + + + Filter... + + + + Shortcut Conflict + + + + Shortcut %1 conflicts with '%2'. Overwrite shortcut? + + + + Cannot generate valid passphrases because the wordlist is too short + + + + Encrypted files are not supported. + لا يتم دعم الملفات المشفرة. + + + Proton Pass Import + استورد Proton Pass + + + Delete plugin data? + حذف بيانات الإضافة؟ + + + Delete plugin data from Entry(s)? + + + + Passkey + + + + Format to use when exporting. Available choices are 'xml', 'csv' or 'html'. Defaults to 'xml'. + + + + start minimized to the system tray + + + + malformed string, possible unescaped delimiter + + + + missing closing delimiter + + + + %1, row: %2, column: %3 + + + + Tags + وسوم + QtIOCompressor @@ -8690,6 +9245,37 @@ This option is deprecated, use --set-key-file instead. خطأ zlib داخلي: + + RemoteHandler + + Command `%1` did not finish in time. Process was killed. + + + + Failed to upload merged database. Command `%1` did not finish in time. Process was killed. + + + + Invalid download parameters provided. + + + + Command `%1` failed to download database. + + + + Invalid database pointer or upload parameters provided. + + + + Command `%1` exited with status code: %2 + + + + Failed to upload merged database. Command `%1` exited with status code: %2 + + + ReportsWidgetBrowserStatistics @@ -8718,11 +9304,11 @@ This option is deprecated, use --set-key-file instead. (Excluded) - + (مستبعد) This entry is being excluded from reports - + تم استبعاد هذا الإدخال من التقارير Please wait, browser statistics is being calculated… @@ -8754,7 +9340,11 @@ This option is deprecated, use --set-key-file instead. Exclude from reports - + استبعاد من التقارير + + + Expire Entry(s)… + Only show entries that have a URL @@ -8762,57 +9352,54 @@ This option is deprecated, use --set-key-file instead. Only show entries that have been explicitly allowed or denied - + أظهِر فقط الإدخالات التي تم السماح بها أو رفضها بشكل صريح Show expired entries - + أظهِر الإدخالات منتهية الصلاحية (Expired) - + (منتهي) + + + Delete plugin data from Entry(s)… + ReportsWidgetHealthcheck - Hover over reason to show additional details. Double-click entries to edit. - تحوم فوق السبب لعرض تفاصيل إضافية. قم بالنقر المزدوج على الإدخالات للتعديل. + Show expired entries + أظهِر الإدخالات منتهية الصلاحية - Bad - Password quality - سيئ + (Expired) + (منتهي) + + + Hover over reason to show additional details. Double-click entries to edit. + تحوم فوق السبب لعرض تفاصيل إضافية. قم بالنقر المزدوج على الإدخالات للتعديل. Bad — password must be changed سيئ - يجب تغيير كلمة المرور - - Poor - Password quality - ضعيف جدا - Poor — password should be changed ضعيف - يجب تغيير كلمة المرور - - Weak - Password quality - ضعيفة - Weak — consider changing the password ضعيف — فكر بتغير كلمة المرور (Excluded) - + (مستبعد) This entry is being excluded from reports - + تم استبعاد هذا الإدخال من التقارير Please wait, health data is being calculated… @@ -8848,26 +9435,22 @@ This option is deprecated, use --set-key-file instead. Exclude from reports - + استبعاد من التقارير - - Show expired entries - + + Expire Entry(s)… + Show entries that have been excluded from reports - - - - (Expired) - + أظهِر الإدخالات التي تم استبعادها من التقارير ReportsWidgetHibp CAUTION: This report requires sending information to the Have I Been Pwned online service (https://haveibeenpwned.com). If you proceed, your database passwords will be cryptographically hashed and the first five characters of those hashes will be sent securely to this service. Your database remains secure and cannot be reconstituted from this information. However, the number of passwords you send and your IP address will be exposed to this service. - + تنبيه: يتطلب هذا التقرير إرسال معلومات إلى خدمة Have I Been Pwned عبر الإنترنت (https://haveibeenpwned.com). إذا تابعت، فسيتم تجزئة كلمات مرور قاعدة بياناتك بطريقة مُعمَّاة وسيتم إرسال الأحرف الخمسة الأولى من هذه التجزئة بشكل آمن إلى هذه الخدمة. تظل قاعدة بياناتك آمنة ولا يمكن إعادة تشكيلها من هذه المعلومات. ومع ذلك، سيتم عرض عدد كلمات المرور التي ترسلها وعنوان IP الخاص بك لهذه الخدمة. Perform Online Analysis @@ -8875,15 +9458,15 @@ This option is deprecated, use --set-key-file instead. Also show entries that have been excluded from reports - + أظهِر أيضًا الإدخالات التي تم استبعادها من التقارير This build of KeePassXC does not have network functions. Networking is required to check your passwords against Have I Been Pwned databases. - + لا يحتوي هذا الإصدار من KeePassXC على وظائف الشبكة. يلزم الاتصال بالشبكة للتحقق من كلمات مرورك في قواعد بيانات Have I Been Pwned. Congratulations, no exposed passwords! - + تهانينا، لا توجد كلمات مرور مكشوفة! Title @@ -8895,15 +9478,15 @@ This option is deprecated, use --set-key-file instead. Password exposed… - + كلمة المرور مُسرّبة… (Excluded) - + (مستبعد) This entry is being excluded from reports - + تم استبعاد هذا الإدخال من التقارير once @@ -8955,7 +9538,11 @@ This option is deprecated, use --set-key-file instead. Exclude from reports - + استبعاد من التقارير + + + Expire Entry(s)… + @@ -9002,11 +9589,11 @@ This option is deprecated, use --set-key-file instead. Show expired entries - + أظهِر الإدخالات منتهية الصلاحية (Expired) - + (منتهي) Export Confirmation @@ -9018,7 +9605,7 @@ This option is deprecated, use --set-key-file instead. Please wait, list of entries with passkeys is being updated… - + الرجاء الانتظار، جارٍ تحديث قائمة الإدخالات التي تحتوي على مفاتيح المرور... No entries with passkeys. @@ -9029,7 +9616,7 @@ This option is deprecated, use --set-key-file instead. ReportsWidgetStatistics Hover over lines with error icons for further information. - + مرّر فوق الخطوط التي تحتوي على أيقونات الأخطاء للحصول على مزيد من المعلومات. Name @@ -9045,11 +9632,11 @@ This option is deprecated, use --set-key-file instead. Database name - + اسم قاعدة البيانات Description - + الوصف Location @@ -9073,7 +9660,7 @@ This option is deprecated, use --set-key-file instead. no - + لا The database was modified, but the changes have not yet been saved to disk. @@ -9093,35 +9680,35 @@ This option is deprecated, use --set-key-file instead. The database contains entries that have expired. - + تحتوي قاعدة البيانات على إدخالات منتهية الصلاحية. Unique passwords - + كلمات مرور فريدة Non-unique passwords - + كلمات مرور غير فريدة More than 10% of passwords are reused. Use unique passwords when possible. - + يتم إعادة استخدام أكثر من 10% من كلمات المرور. استخدم كلمات مرور فريدة عندما يكون ذلك ممكنًا. Maximum password reuse - + الحد الأقصى لإعادة استخدام كلمة المرور Some passwords are used more than three times. Use unique passwords when possible. - + يتم استخدام بعض كلمات المرور أكثر من ثلاث مرات. استخدم كلمات مرور فريدة عندما يكون ذلك ممكنًا. Number of short passwords - + عدد كلمات المرور القصيرة Recommended minimum password length is at least 8 characters. - + الحد الأدنى الموصى به لطول كلمة المرور هو 8 أحرف على الأقل. Number of weak passwords @@ -9129,19 +9716,19 @@ This option is deprecated, use --set-key-file instead. Recommend using long, randomized passwords with a rating of 'good' or 'excellent'. - + نوصي باستخدام كلمات مرور طويلة وعشوائية بتقييم "جيد" أو "ممتاز". Entries excluded from reports - + الإدخالات المستبعدة من التقارير Excluding entries from reports, e. g. because they are known to have a poor password, isn't necessarily a problem but you should keep an eye on them. - + باستثناء الإدخالات من التقارير، مثال: نظرًا لأنه من المعروف أن كلمات المرور الخاصة بهم سيئة، فهذا لا يمثل مشكلة بالضرورة ولكن يجب عليك مراقبتهم. Average password length - + متوسط ​​طول كلمة المرور %1 characters @@ -9149,22 +9736,22 @@ This option is deprecated, use --set-key-file instead. Average password length is less than ten characters. Longer passwords provide more security. - + متوسط ​​طول كلمة المرور أقل من عشرة أحرف. توفر كلمات المرور الأطول مزيدًا من الأمان. SSHAgent Agent connection failed. - + فشل اتصال العميل. Agent protocol error. - + خطأ في بروتوكول العميل. No agent running, cannot add identity. - + لا يوجد عميل قيد التشغيل، ولا يمكن إضافة هوية. Key identity ownership conflict. Refusing to add. @@ -9172,7 +9759,7 @@ This option is deprecated, use --set-key-file instead. Agent refused this identity. Possible reasons include: - + رفض العميل هذه الهوية. تشمل الأسباب المحتملة ما يلي: The key has already been added. @@ -9180,22 +9767,30 @@ This option is deprecated, use --set-key-file instead. Restricted lifetime is not supported by the agent (check options). - + لا يدعم العميل مدة الحياة المقيدة (حدد الخيارات). A confirmation request is not supported by the agent (check options). - + طلب التأكيد غير مدعوم من قبل الوكيل (حدد الخيارات). Security keys are not supported by the agent or the security key provider is unavailable. - + مفاتيح الأمان غير مدعومة من قبل الوكيل أو أن موفر مفتاح الأمان غير متوفر. No agent running, cannot remove identity. - + لا يوجد عميل قيد التشغيل، ولا يمكن إزالة الهوية. No agent running, cannot list identities. + لا يوجد عميل قيد التشغيل، ولا يمكن إدراج الهويات. + + + Failed to remove all SSH identities from agent. + + + + All SSH identities removed from agent. @@ -9275,7 +9870,7 @@ This option is deprecated, use --set-key-file instead. Case sensitive - + حساس لحالة الأحرف Limit search to selected group @@ -9298,7 +9893,7 @@ This option is deprecated, use --set-key-file instead. Manage - + أدِر @@ -9313,7 +9908,7 @@ This option is deprecated, use --set-key-file instead. Manage - + أدِر @@ -9332,7 +9927,7 @@ This option is deprecated, use --set-key-file instead. Show notification when passwords are retrieved by clients - + أظهِر الإشعارات عند استرداد كلمات المرور من قبل العملاء <html><head/><body><p>If enabled, any attempt to read a password must be confirmed. Otherwise, clients can read passwords without confirmation when the database is unlocked.</p><p>This option only covers the access to the password of an entry. Clients can always enumerate the items of exposed databases and query their attributes.</p></body></html> @@ -9340,7 +9935,7 @@ This option is deprecated, use --set-key-file instead. Confirm when passwords are retrieved by clients - + تأكيد متى يتم استرداد كلمات المرور من قبل العملاء Confirm when clients request entry deletion @@ -9348,7 +9943,7 @@ This option is deprecated, use --set-key-file instead. Prompt to unlock database before searching - + المطالبة بإلغاء قفل قاعدة البيانات قبل البحث Exposed database groups: @@ -9356,7 +9951,7 @@ This option is deprecated, use --set-key-file instead. Authorization - + التفويض These applications are currently connected: @@ -9364,7 +9959,7 @@ This option is deprecated, use --set-key-file instead. <b>Warning:</b> - + <b>تحذير:</b> Save current changes to activate the plugin and enable editing of this section. @@ -9376,14 +9971,14 @@ This option is deprecated, use --set-key-file instead. <html><head/><body><p>This improves compatibility with certain applications which search for password without unlocking the database first.</p><p>But enabling this may also crash the client if the database can not be unlocked within a certain timeout. (Usually 25s, but may be a different value set in applications.) </p></body></html> - + <html><head/><body><p>يؤدي ذلك إلى تحسين التوافق مع بعض التطبيقات التي تبحث عن كلمة المرور دون فتح قاعدة البيانات أولاً. </p><p> لكن تمكين هذا قد يؤدي أيضًا إلى تعطل العميل إذا تعذر إلغاء قفل قاعدة البيانات خلال مهلة معينة. (عادةً 25 ثانية، ولكن قد يتم تعيين قيمة مختلفة في التطبيقات.) </p></body></html> SettingsWidgetKeeShare Active - + نشط Allow KeeShare imports @@ -9395,7 +9990,7 @@ This option is deprecated, use --set-key-file instead. Allow KeeShare exports - + اسمح بتصدير KeeShare Allow export @@ -9407,7 +10002,7 @@ This option is deprecated, use --set-key-file instead. Own certificate - + شهادة خاصة Signer: @@ -9438,14 +10033,14 @@ This option is deprecated, use --set-key-file instead. ShareExport Could not write export container. - + لم يتمكن من كتابة حاوية التصدير. ShareImport Successful import - + نجح الاستيراد @@ -9468,42 +10063,19 @@ This option is deprecated, use --set-key-file instead. Conflicting export target path %1 in %2 - + مسار هدف التصدير المتعارض %1 في %2 Export to %1 failed (%2) - + فشل التصدير إلى %1 (%2) Export to %1 successful (%2) - + صُدّر إلى %1 بنجاح (%2) Export to %1 - - - - - ShortcutSettingsWidget - - Double click an action to change its shortcut - - - - Shortcut Conflict - - - - Filter... - - - - Shortcut %1 conflicts with '%2'. Overwrite shortcut? - - - - Reset Shortcuts - + صدّر إلى %1 @@ -9568,11 +10140,11 @@ This option is deprecated, use --set-key-file instead. NOTE: These TOTP settings are custom and may not work with other authenticators. TOTP QR code dialog warning - + ملاحظة: إعدادات TOTP هذه مخصّصة وقد لا تعمل مع الموثقين الآخرين. There was an error creating the QR code. - + حدث خطأ أثناء إنشاء رمز QR. Closing in %1 seconds. @@ -9587,7 +10159,7 @@ This option is deprecated, use --set-key-file instead. Secret Key: - + المفتاح السري: Secret key must be in Base32 format @@ -9599,7 +10171,7 @@ This option is deprecated, use --set-key-file instead. Default settings (RFC 6238) - + الإعدادات الافتراضية (RFC 6238) Steam® settings @@ -9640,7 +10212,7 @@ This option is deprecated, use --set-key-file instead. Invalid TOTP Secret - + سر TOTP غير صالح You have entered an invalid secret key. The key must be in Base32 format. @@ -9649,11 +10221,11 @@ Example: JBSWY3DPEHPK3PXP Confirm Remove TOTP Settings - + أكّد إزالة إعدادات TOTP Are you sure you want to delete TOTP settings for this entry? - + هل أنت متأكد أنك تريد حذف إعدادات TOTP لهذا الإدخال؟ @@ -9667,11 +10239,11 @@ Example: JBSWY3DPEHPK3PXP UpdateCheckDialog Checking for updates - + جارِ التحقق من وجود تحديثات Checking for updates… - + جارِ التحقق من وجود تحديثات… Close @@ -9679,19 +10251,19 @@ Example: JBSWY3DPEHPK3PXP Software Update - + تحديث النظام An error occurred when trying to retrieve update information, please try again later. - + حدث خطأ أثناء محاولة استرداد معلومات التحديث، يرجى المحاولة مرة أخرى لاحقًا. <strong>A new version is available.</strong><br/>KeePassXC %1 can be <a href="https://keepassxc.org/download/">downloaded here</a>. - + <strong>تتوفر نسخة جديدة.</strong><br/>KeePassXC %1 يمكن <a href="https://keepassxc.org/download/">تنزيلها هنا</a>. You have the latest version of KeePassXC - + لديك أحدث إصدار من KeePassXC @@ -9718,11 +10290,11 @@ Example: JBSWY3DPEHPK3PXP Open Database - + افتح قاعدة بيانات Import File - + استورد الملف @@ -9748,7 +10320,7 @@ Example: JBSWY3DPEHPK3PXP Could not find interface for hardware key with serial number %1. Please connect it to continue. - + لم نتمكن من العثور على واجهة لمفتاح حماية عتادي بالرقم التسلسلي %1. يرجى توصيله للمتابعة. @@ -9763,7 +10335,7 @@ Example: JBSWY3DPEHPK3PXP Selected hardware key slot does not support challenge-response! - + فتحة مفتاح الحماية العتادية المُحددة لا تدعم ميزة التحدي والاستجابة! Challenge-Response @@ -9794,11 +10366,15 @@ Example: JBSWY3DPEHPK3PXP يم يتم الكشف عن أي مفتاح الأجهزة - <p>If you own a <a href="https://www.yubico.com/">YubiKey</a> or <a href="https://onlykey.io">OnlyKey</a>, you can use it for additional security.</p><p>The key requires one of its slots to be programmed as <a href="https://docs.yubico.com/yesdk/users-manual/application-otp/challenge-response.html">HMAC-SHA1 Challenge-Response</a>.</p> + Refresh hardware keys + أنعش مفاتيح الحماية العتادية + + + <p>If you own a <a href="https://www.yubico.com/">YubiKey</a> or <a href="https://onlykey.io">OnlyKey</a>, you can use it for additional security.</p><p>The key requires one of its slots to be programmed with <a href="https://keepassxc.org/docs/#faq-yubikey-howto">Challenge-Response</a>.</p> - Refresh hardware keys + Hardware keys found, but no slots are configured @@ -9810,15 +10386,15 @@ Example: JBSWY3DPEHPK3PXP Could not find or access hardware key with serial number %1. Please present it to continue. - + تعذر العثور على مفتاح حماية عتادي الذي يحمل الرقم التسلسلي %1 أو الوصول إليه. يرجى تقديمه للمتابعة. Hardware key is locked or timed out. Unlock or re-present it to continue. - + مفتاح حماية عتادي مُقفل أو انتهت مهلته. قم بإلغاء قفله أو إعادة تقديمه للمتابعة. Hardware key was not found or is not configured. - + لم يتم العثور على مفتاح حماية عتادي أو لم يتم تكوينه. Failed to complete a challenge-response, the PCSC error code was: %1 @@ -9862,15 +10438,15 @@ Example: JBSWY3DPEHPK3PXP Could not find hardware key with serial number %1. Please plug it in to continue. - + لم نتمكن من العثور على مفتاح حماية عتادي بالرقم التسلسلي %1. يرجى توصيله للمتابعة. Hardware key timed out waiting for user interaction. - + انتهت مهلة مفتاح حماية عتادي في انتظار تفاعل المستخدم. A USB error occurred when accessing the hardware key: %1 - + حدث خطأ USB عند الوصول إلى المفتاح الحماية العتادي: %1 Failed to complete a challenge-response, the specific error was: %1 diff --git a/share/translations/keepassxc_bg.ts b/share/translations/keepassxc_bg.ts index ead064655..87173aecc 100644 --- a/share/translations/keepassxc_bg.ts +++ b/share/translations/keepassxc_bg.ts @@ -217,18 +217,50 @@ You must restart the application to set the new language. Would you like to restart now? За да настроите нов език, приложението трябва да рестартира. Желаете ли приложението да рестартира сега? - - Reset Settings? - Да бъдат ли нулирани настройките? - - - Are you sure you want to reset all general and security settings to default? - Желаете ли основните настройки и настройките на сигурността да бъдат нулирани? - Select backup storage directory Изберете папка, в която да бъдат за запазвани резервните копия + + Confirm Reset + Потвърждаване на нулиране + + + Are you sure you want to reset all settings to default? + Желаете ли всички настройки да бъдат нулирани? + + + Import KeePassXC Settings + Внасяне на настройки на KeePassXC + + + Failed to import settings from %1, not a valid settings file. + Грешка при внасяне на настройки от %1: не е приемлив файл с настройки. + + + Export KeePassXC Settings + Изнасяне на настройки на KeePassXC + + + Small + Малък + + + Normal + Стандартен + + + Medium + Среден + + + Large + Голям + + + Custom + Потребителски + ApplicationSettingsWidgetGeneral @@ -270,7 +302,7 @@ Remember database key files and security dongles - Запомняне на файловете-ключ и преносимите защитни устройства за хранилищата + Запомняне на файловете с ключ и преносимите защитни устройства за хранилищата Check for updates at application startup once per week @@ -280,25 +312,6 @@ Include beta releases when checking for updates При проверка за обновяване да се проверяват и бета изданията - - On database unlock, show entries that - При отключване на хранилище се показват записите - - - have expired - On database unlock, show entries that... - с изтекла давност - - - days - On database unlock, show entries that will expire within %1 days - дни - - - will expire within - On database unlock, show entries that... - с давност до - File Management Управление на файлове @@ -323,22 +336,10 @@ Backup database file before saving Резервно копие на хранилището преди запазване - - Backup destination - Път към резервно копие - - - Specifies the database backup file location. Occurrences of "{DB_FILENAME}" are replaced with the filename of the saved database without extension. {TIME:<format>} is replaced with the backup time, see https://doc.qt.io/qt-5/qdatetime.html#toString. <format> defaults to format string "dd_MM_yyyy_hh-mm-ss". - Указва местонахождението на файла, съдържащ резервното копие на хранилището. Където се среща низът „{DB_FILENAME}“ се заменя с името на файла на запазеното хранилище без разширението. {TIME:<format>} се заменя с времето на създаване на резервното копие, повече на https://doc.qt.io/qt-5/qdatetime.html#toString. <format> връща формата на низа по подразбиране: „dd_MM_yyyy_hh-mm-ss“. - {DB_FILENAME}.old.kdbx {DB_FILENAME}.old.kdbx - - Choose... - Избиране… - Use alternative saving method (may solve problems with Dropbox, Google Drive, GVFS, etc.) Използване на алтернативен метод за запазване (при проблеми с Dropbox, Google Drive, GVFS, и т.н.) @@ -487,7 +488,7 @@ ms Milliseconds - мс + мс Auto-Type typing delay: @@ -505,6 +506,71 @@ Remember last typed entry for: Запомняне на последния въведен запис за: + + On database unlock, show entries that will expire within + При отключване на хранилище се показват записите, с изтичаща валидност след + + + On database unlock, show entries that will expire within + При отключване на хранилище се показват записите, с изтичаща валидност след + + + days + number of days warning for password expiration + дни + + + Destination format: + Целеви формат: + + + <html><head/><body><p><span style=" font-weight:600;">{DB_FILENAME}</span> is replaced with the filename of the saved database without extension</p><p><span style=" font-weight:600;">{TIME:&lt;format&gt;}</span> is replaced with the specified time format (default: dd_MM_yyyy_hh-mm-ss)</p><p>See the User Guide for more details</p></body></html> + <html><head/><body><p><span style=" font-weight:600;">{DB_FILENAME}</span> се заменя с името на файла на хранилището, но без разширението</p><p><span style=" font-weight:600;">{TIME:&lt;format&gt;}</span> се заменя с избрания формат на датата (стандартно: dd_MM_yyyy_hh-mm-ss)</p><p>За подробности прочетете ръководството на потребителя</p></body></html> + + + Choose folder... + Избиране на папка… + + + Show confirmation before moving entries to recycle bin + Потвърждаване при преместване на записи в кошчето + + + Copy data on double clicking field in entry view + Копиране на данните при двойно щракване върху поле в изгледа за въвеждане + + + Show toolbar + Лентата с инструменти + + + Show the menu bar by pressing the Alt key + При натискане на клавиш Alt се показва лентата с менюто + + + Show menubar + Лента с менюто + + + Import settings… + Внасяне на настройки… + + + Export settings… + Изнасяне на настройки… + + + Open browser on double clicking URL field in entry view + Отваряне на мрежовия четец при двойно щракване върху интернет адрес в изгледа за въвеждане + + + Font size: + Размер на шрифта + + + Font size selection + Списък с размери на шрифта + ApplicationSettingsWidgetSecurity @@ -568,19 +634,7 @@ Hide passwords in the entry preview panel - Премахване на паролите от панела за преглед на записи - - - Hide entry notes by default - Бележките са скрити по подразбиране - - - Move entries to recycle bin without confirmation - Преместване на записите в кошчето без потвърждаване - - - Enable double click to copy the username/password entry columns - Двукратното щракване копира потребителско име/парола + Скриване на паролите в панела за преглед на запис Privacy @@ -592,7 +646,19 @@ Hide TOTP in the entry preview panel - Премахване на TOTP от панела за преглед на записи + Скриване на TOTP в панела за преглед на запис + + + Lock databases when switching user + Заключване на хранилищата при смяна на потребител + + + Lock Options + Настройки на заключване + + + Hide notes in the entry preview panel + Скриване на бележката в панела за преглед на запис @@ -641,20 +707,6 @@ Entry does not have attribute for PICKCHARS: %1 Записът няма атрибут за PICKCHARS: %1 - - Invalid conversion type: %1 - Неправилен тип на преобразуване: %1 - - - Invalid conversion syntax: %1 - Неправилен синтаксис на преобразуване: %1 - - - Invalid regular expression syntax %1 -%2 - Неправилен синтаксис на регулярен израз %1 -%2 - Invalid placeholder: %1 Неправилен заместител: %1 @@ -886,24 +938,25 @@ Please select the correct database for saving credentials. Add to existing entry - + Добавяне към запис Existing passkey found. Do you want to register a new passkey for: - + Съществува друг passkey. +Желаете ли да регистрирате нов passkey за: Select the existing passkey and press Update to replace it. - + Изберете съществуващ passkey и изберете „Обновяване“, за да бъде заменен. Authenticate passkey credentials for: - + Удостоверяване на самоличността на passkey за: Do you want to register a passkey for: - + Желаете ли да регистрирате passkey за: @@ -988,16 +1041,17 @@ Do you want to delete the entry? Register a new passkey to this entry: - + Регистриране на нов passkey за този запис: KeePassXC - Update passkey - + KeePassXC - Обновяване на passkey Entry already has a passkey. Do you want to overwrite the passkey in %1 - %2? - + Записът има passkey. +Желаете ли този passkey да бъде презаписан в %1 - %2? Register @@ -1016,16 +1070,12 @@ Do you want to overwrite the passkey in %1 - %2? Enable browser integration - Разрешаване на съчетаването с мрежовия четец + Разрешаване на съчетаване с мрежови четци General Основни - - Browsers installed as snaps are currently not supported. - Мрежови четци, инсталирани от пакети на Snap не се поддържат. - Enable integration for these browsers: Съчетаване с мрежови четци: @@ -1085,11 +1135,11 @@ Do you want to overwrite the passkey in %1 - %2? Returns expired credentials. String [expired] is added to the title. - Връща самоличност с изтекла давност. Към заглавието е добавен низът „[изтекъл]“. + Връща самоличност с изтекла давност. Към заглавието е добавен низът „(изтекла давност)“. Allow returning expired credentials - Позволяване на връщане на самоличности с изтекла давност + Връщане и на записи с изтекла давност All databases connected to the extension will return matching credentials. @@ -1197,18 +1247,6 @@ Do you want to overwrite the passkey in %1 - %2? Custom extension ID Идентификатор на разширение - - Due to Snap sandboxing, you must run a script to enable browser integration.<br />You can obtain this script from %1 - Поради изолирането при пакетите от Snap, трябва да изпълните скрипт, който да разреши съчетаване с мрежовия четец.<br />Можете да получите скрипта от %1 - - - KeePassXC-Browser is needed for the browser integration to work. <br />Download it for %1 and %2 and %3. %4 - Разширението KeePassXC-Browser е необходимо, за да работи съчетаването с мрежовия четец.<br />Изтеглете за %1 и %2 и %3. %4 - - - Please see special instructions for browser extension use below - Вижте специалните инструкции за използване на разширението на мрежовия четец - Executable Files Изпълними файлове @@ -1251,11 +1289,19 @@ Do you want to overwrite the passkey in %1 - %2? Allows using insecure http://localhost with passkeys for testing purposes. - + Позволява използване на незащитения адрес http://localhost с passkeys с цел изпитания Allow using localhost with passkeys - + Използване на passkeys през localhost + + + KeePassXC-Browser is needed for the browser integration to work. <br />Download it for %1 and %2 and %3. + Разширението KeePassXC-Browser е необходимо, за да работи съчетаването с мрежовия четец.<br />Изтеглете за %1 и %2 и %3. + + + Browsers installed using Snap or Flatpak are not supported with exception to Firefox installed using Snap. + Не се поддържат мрежови четци, инсталирани от Снап или Флатпак, с изключение на Firefox, инсталиран от Снап. @@ -1399,6 +1445,20 @@ Do you want to overwrite the passkey in %1 - %2? Imported from CSV file: %1 Внесено от файл с разделители: %1 + + No Title Selected + Не е избрано заглавие + + + No title column was selected, entries will be hard to tell apart. +Are you sure you want to import? + Не е избрана колона за заглавие, следователно записите ще бъдат трудни за разграничаване. +Желаете ли внасянето да бъде извършено? + + + Tags + Етикети + CsvParserModel @@ -1462,6 +1522,14 @@ Backup database located at %2 Recycle Bin Кошче + + Database file read error. + Грешка при четене на файла на хранилището. + + + No file path was provided. + Не е зададен път до файл. + DatabaseOpenDialog @@ -1490,11 +1558,11 @@ Backup database located at %2 Key file to unlock the database - Файл-ключ за отключване на хранилището + Файл с ключ за отключване на хранилището Browse for key file - Избор на файл-ключ + Избор на файл с ключ Browse… @@ -1562,7 +1630,7 @@ To prevent this error from appearing, you must go to "Database Settings / S Failed to open key file: %1 - Грешка при отваряне на файл-ключ: %1 + Грешка при отваряне на файл с ключ: %1 Old key file format @@ -1582,15 +1650,15 @@ To prevent this error from appearing, you must go to "Database Settings / S Key files - Файл-ключове + Файлове с ключ Select key file - Избор на файл-ключ + Избор на файл с ключ Cannot use database file as key file - Файл на хранилище не може да бъде използван като файл-ключ. + Файл на хранилище не може да бъде използван като файл с ключ. authenticate to access the database @@ -1608,14 +1676,6 @@ To prevent this error from appearing, you must go to "Database Settings / S <p>In addition to a password, you can use a secret file to enhance the security of your database. This file can be generated in your database's security settings.</p><p>This is <strong>not</strong> your *.kdbx database file!</p> <p>В допълнение към паролата, можете да използвате таен файл за подобряване на защитата на хранилището. Този файл може да бъде създаден в настройките за защита на хранилището.</p><p>Това <strong>не</strong> е файл на *.kdbx с хранилище!</p> - - Click to add a key file. - За да добавите файл с ключ щракнете тук. - - - <a href="#" style="text-decoration: underline">I have a key file</a> - <a href="#" style="text-decoration: underline">Имам файл с ключ</a> - Use hardware key [Serial: %1] Използване на хардуерен ключ [Сериен № %1] @@ -1650,6 +1710,18 @@ Are you sure you want to continue with this file?. Refresh Hardware Keys Презареждане на хардуерните ключове + + Click to add a key file. + За да добавите файл с ключ щракнете тук. + + + <a href="#" style="text-decoration: underline">I have a key file</a> + <a href="#" style="text-decoration: underline">Имам файл с ключ</a> + + + Hardware keys found, but no slots are configured. + Открити са хардуерни ключове, но без настроени слотове. + DatabaseSettingWidgetMetaData @@ -1674,16 +1746,32 @@ Are you sure you want to continue with this file?. Encryption Settings - Настройки на шифроване + Настройки на шифроването Browser Integration - Съчетаване с мрежовия четец + Съчетаване с мрежов четец Maintenance Профилактика + + KeeShare + KeeShare + + + Secret Service Integration + Съчетаване с Услуга за тайни + + + Remote Sync + Отдалечено синхронизиране + + + Database Settings: %1 + Настройки на хранилището: %1 + DatabaseSettingsWidgetBrowser @@ -1697,7 +1785,7 @@ Are you sure you want to continue with this file?. Forget all site-specific settings on entries - Премахване на всички специфични за страниците настройки на записите + Премахване на специфичните за страници настройки от записите Refresh database root group ID @@ -1757,7 +1845,7 @@ This may prevent connection to the browser plugin. Successfully removed %n encryption key(s) from KeePassXC settings. - Успешно отстранен %n шифроващ ключ от настройките на KeePassXC.Успешно отстранен %n ключ(а) за шифроване от настройките на KeePassXC. + Успешно е отстранен %n шифроващ ключ от настройките на KeePassXC.Успешно са отстранени %n шифроващи ключа от настройките на KeePassXC. Do you really want forget all site-specific settings on every entry? @@ -1793,7 +1881,7 @@ This is only necessary if your database is a copy of another and the browser ext Convert legacy KeePassHTTP attributes to KeePassXC-Browser compatible custom data - Преобразуване на стари KeePassHTTP свойствa в съвместими с KeePassXC-Browser такива + Преобразуване на изведени от употреба атрибути на KeePassHTTP в съвместими с KeePassXC-Browser No keys found @@ -1854,14 +1942,14 @@ Are you sure you want to continue without a password? Weak password Слаба парола - - You must enter a stronger password to protect your database. - За да защитите хранилището трябва по-добра парола. - This is a weak password! For better protection of your secrets, you should choose a stronger password. Това е слаба парола! За по-добра защита на вашите тайни, трябва да изберете по-силна парола. + + The provided password does not meet the minimum quality requirement. + Паролата не отговаря на минималните изисквания за качество. + DatabaseSettingsWidgetEncryption @@ -1935,11 +2023,11 @@ Are you sure you want to continue without a password? Parallelism: - Паралелно изпълняване: + Паралелно изпълнение: Parallelism - Паралелно изпълняване + Паралелно изпълнение KDBX 4 (recommended) @@ -1999,11 +2087,11 @@ If you keep this number, your database will not be protected from brute force at thread(s) Threads for parallel execution (KDF settings) - резба(и) нишка(и) + нишка нишки Encryption Settings: - Настройки на шифроване: + Настройки на шифроването: Basic @@ -2155,12 +2243,56 @@ removed from the database. min - мин + мин Autosave delay since last change checkbox Отметка на изчакването на автоматичното запазване след промяна + + Public Database Metadata + Публични описателни данни на хранилището + + + Warning: the following settings are not encrypted. + Внимание: следните настройки не са шифровани. + + + Display name: + Име: + + + Publically visible display name used on the unlock dialog + Общодостъпно име, използвано в диалога за отключване + + + Database public display name + Публично име на хранилището + + + Display color: + Цвят: + + + Publically visible color used on the unlock dialog + Общодостъпен цвят, използван в диалога за отключване + + + Database public display color chooser + Контрол за избор на цвят на хранилището + + + Clear + Изчистване + + + Display icon: + Пиктограма: + + + Select Database Icon + Избор на пиктограма на хранилището + DatabaseSettingsWidgetKeeShare @@ -2222,7 +2354,7 @@ removed from the database. Custom Icons Are In Use - Потребителски пиктограми се използват + Потребителските пиктограми се използват All custom icons are in use by at least one entry or group. @@ -2256,6 +2388,140 @@ removed from the database. Поле за описание на хранилището + + DatabaseSettingsWidgetRemote + + Sync Commands + Команди за извършване на синхронизиране + + + Remove + Премахване + + + Command Settings + Настройки на команда + + + Name + Име + + + Save + Запазване + + + Download + Изтегляне + + + Command: + Команда: + + + Download command field + Поле за командата за изтегляне + + + e.g.: "sftp user@hostname" or "scp user@hostname:DatabaseOnRemote.kdbx {TEMP_DATABASE}" + напр.: „sftp user@hostname“ или „scp user@hostname:отдалечено-хранилище.kdbx {TEMP_DATABASE}“ + + + Input: + Въвеждане: + + + Download input field + Поле за въвеждане при изтегляне + + + Upload + Качване + + + Upload command field + Поле за командата за качване + + + e.g.: "sftp user@hostname" or "scp {TEMP_DATABASE} user@hostname:DatabaseOnRemote.kdbx" + напр.: „sftp user@hostname“ или „scp {TEMP_DATABASE} user@hostname:отдалечено-хранилище.kdbx“ + + + Upload input field + Поле за въвеждане при качване + + + Name cannot be empty. + Името не трябва да бъде празно. + + + Test + Проверяване + + + Download command cannot be empty. + Командата за изтегляне не трябва да бъде празна. + + + Download failed with error: %1 + Грешка при изтегляне: %1 + + + Download finished, but file %1 could not be found. + Изтеглянето приключи, но файлът %1 не може да бъде намерен. + + + Download successful. + Изтеглянето е успешно. + + + Save Remote Settings + Запазване на отдалечени настройки + + + You have unsaved changes. Do you want to save them? + Има незапазени промени. Желаете ли да бъдат запазени? + + + e.g.: +get DatabaseOnRemote.kdbx {TEMP_DATABASE} +exit +--- +{TEMP_DATABASE} is used as placeholder to store the database in a temporary location +The command has to exit. In case of `sftp` as last command `exit` has to be sent + + напр.: +get отдалечено-хранилище.kdbx {TEMP_DATABASE} +exit +--- +Низът {TEMP_DATABASE} се използва за заместител на временното местоположение на хранилището +Командата трябва да завърши. В случая на `sftp` последната изпратена команда трябва да бъде `exit` + + + e.g.: +put {TEMP_DATABASE} DatabaseOnRemote.kdbx +exit +--- +{TEMP_DATABASE} is used as placeholder to store the database in a temporary location +The command has to exit. In case of `sftp` as last command `exit` has to be sent + + напр.: +put {TEMP_DATABASE} отдалечено-хранилище.kdbx +exit +--- +Низът {TEMP_DATABASE} се използва за заместител на временното местоположение на хранилището +Командата трябва да завърши. В случая на `sftp` последната изпратена команда трябва да бъде `exit` + + + + Timeout: + Време на изчакване: + + + seconds + секунди + + DatabaseTabWidget @@ -2329,6 +2595,11 @@ This is definitely a bug, please report it to the developers. Database tab name modifier %1 [Заключено] + + %1 [Temporary] + Database tab name modifier + %1 [Временно] + DatabaseWidget @@ -2452,26 +2723,6 @@ Save changes? File has changed Файлът е променен - - The database file has changed. Do you want to load the changes? - Файлът с хранилището е променен. Желаете ли промените да бъдат заредени? - - - Merge Request - Заявка за сливане - - - The database file has changed and you have unsaved changes. -Do you want to merge your changes? - Файлът с хранилището е променен, а имате незаписани промени. -Желаете ли да промените да бъдат сляти? - - - Could not open the new database file while attempting to autoreload. -Error: %1 - При опит за автоматично презареждане новият файл на хранилището не е отворен. -Грешка: %1 - Disable safe saves? Забраняване на безопасно запазване? @@ -2523,6 +2774,86 @@ Disable safe saves and try again? Database tab name modifier %1 [Ново хранилище] + + Remote Sync did not contain any download or upload commands. + Отдалеченото синхронизиране не съдържа команди за изтегляне или качване. + + + Remote sync '%1' completed successfully! + Отдалеченото синхронизиране „%1“ завърши! + + + Remote sync '%1' failed: %2 + Отдалеченото синхронизиране „%1“ завърши с грешка: %2 + + + Error while saving database %1: %2 + Грешка при запазване на хранилището %1: %2 + + + Downloading... + Изтегляне... + + + Uploading... + Качване… + + + Syncing... + Синхронизиране… + + + Remove passkey from entry + Премахване на passkey от запис + + + Do you want to remove the passkey from this entry? + Желаете ли този passkey да бъде премахнат от записа? + + + The database file "%1" was modified externally + Файлът на хранилището „%1“ е променен от друго приложение + + + Do you want to load the changes? + Желаете ли промените да бъдат заредени? + + + Reload database + Презареждане на хранилището + + + Reloading database… + Презареждане на хранилището… + + + Reload canceled + Презареждането е прекъснато + + + Reload successful + Успешно презаредено + + + Reload pending user action… + Презареждането изчаква действие от потребителя… + + + The database file "%1" was modified externally.<br>How would you like to proceed?<br><br>Merge all changes<br>Ignore the changes on disk until save<br>Discard unsaved changes + Файлът на хранилището „%1“ е променен от друго приложение<br>Как желаете да продължите?<br><br>Сливане на промените<br>Пренебрегване на промените на диска до запазване<br>Отказ от незапазените промени + + + The database file "%1" was modified externally.<br>How would you like to proceed?<br><br>Merge all changes then save<br>Overwrite the changes on disk<br>Discard unsaved changes + Файлът на хранилището „%1“ е променен от друго приложение<br>Как желаете да продължите?<br><br>Сливане на промените<br>Презаписване на промените на диска<br>Отказ от незапазените промени + + + Database file overwritten. + Файлът на хранилището е презаписан. + + + Database file on disk cannot be unlocked with current credentials.<br>Enter new credentials and/or present hardware key to continue. + Файлът на хранилището не може да бъде отключено с текущите данни за отключване.<br>За да продължите въведете данните за отключване и/или включете хардуерен ключ. + EditEntryWidget @@ -2574,10 +2905,6 @@ Disable safe saves and try again? n/a липсва - - (encrypted) - (шифровано) - Select private key Избор на частен ключ @@ -2638,7 +2965,7 @@ Would you like to correct it? Would you like to save changes to this entry? - Желаете ли промените в записа да бъдат запазени? + Желаете ли промените на записа да бъдат запазени? New attribute @@ -2680,6 +3007,10 @@ Would you like to correct it? %n year(s) %n година%n години + + Failed to decrypt SSH key, ensure password is correct. + Грешка при разшифроване на ключа на SSH, уверете се, че паролата е вярна. + EditEntryWidgetAdvanced @@ -2851,18 +3182,10 @@ Would you like to correct it? Skip Auto-Submit for this entry Без автоматично изпращане на формуляр с този запис - - Only send this setting to the browser for HTTP Auth dialogs. If enabled, normal login forms will not show this entry for selection. - Изпраща към мрежовия четец този запис само при диалози за HTTP Auth. Ако е отметнато, този запис няма да е достъпен за обикновените формуляри за вход. - Use this entry only with HTTP Basic Auth Използване на записа само с HTTP Basic Auth - - Do not send this setting to the browser for HTTP Auth dialogs. If enabled, HTTP Auth dialogs will not show this entry for selection. - Не изпраща към мрежовия четец този запис при диалози за HTTP Auth. Ако е отметнато, този запис няма да е достъпен за диалозите за HTTP Auth. - Do not use this entry with HTTP Basic Auth Без използване на записа с HTTP Basic Auth @@ -2887,6 +3210,14 @@ Would you like to correct it? Additional URLs Допълнителни адреси + + Only send this entry to the browser for HTTP Auth dialogs. If enabled, normal login forms will not show this entry for selection. + Изпраща към мрежовия четец този запис само при диалози за HTTP Auth. Ако е отметнато, този запис няма да е достъпен за обикновените формуляри за вход. + + + Do not send this entry to the browser for HTTP Auth dialogs. If enabled, HTTP Auth dialogs will not show this entry for selection. + Не изпраща към мрежовия четец този запис при диалози за HTTP Auth. Ако е отметнато, този запис няма да е достъпен за диалозите за HTTP Auth. + EditEntryWidgetHistory @@ -3058,7 +3389,7 @@ Would you like to correct it? External key file - Външен файл-ключ + Външен файл с ключ Add to agent @@ -3074,7 +3405,7 @@ Would you like to correct it? Browser for key file - Избор на файл-ключ + Избор на файл с ключ Browse… @@ -3109,6 +3440,10 @@ Would you like to correct it? seconds секунди + + Clear agent + Изчистване на агента + EditGroupWidget @@ -3551,6 +3886,24 @@ This may cause the affected plugins to malfunction. %1 - Clone %1 - копие + + Passkey + Passkey + + + Invalid conversion type: %1 + Неправилен тип на преобразуване: %1 + + + Invalid conversion syntax: %1 + Неправилен синтаксис на преобразуване: %1 + + + Invalid regular expression syntax %1 +%2 + Неправилен синтаксис на регулярен израз %1 +%2 + EntryAttachments @@ -3559,6 +3912,21 @@ This may cause the affected plugins to malfunction. Файлът „%1“ не може да бъде отворен + + EntryAttachmentsDialog + + Form + Формуляр + + + File name + Име на файл + + + File contents... + Съдържание… + + EntryAttachmentsModel @@ -3596,14 +3964,6 @@ This may cause the affected plugins to malfunction. Remove Премахване - - Rename selected attachment - Преименуване на избрания прикачен файл - - - Rename - Преименуване - Open selected attachment Отваряне на избрания прикачен файл @@ -3720,6 +4080,18 @@ Would you like to overwrite the existing attachment? Желаете ли Желаете ли съществуващият прикачен файл да бъде презаписан? + + New + Добавяне + + + Preview + Преглед + + + Failed to preview an attachment: Attachment not found + Грешка: прикачен файл не е намерен + EntryAttributesModel @@ -3784,7 +4156,7 @@ Would you like to overwrite the existing attachment? Expiration - Давност + Изтичаща давност TOTP @@ -3868,7 +4240,7 @@ Would you like to overwrite the existing attachment? Group name - Име на група + Име на групата Entry title @@ -3918,6 +4290,10 @@ Would you like to overwrite the existing attachment? Background Color Цвят на фона + + Group Path + Път на групата + EntryPreviewWidget @@ -3943,7 +4319,7 @@ Would you like to overwrite the existing attachment? Expiration - Давност + Изтичаща давност Tags @@ -4312,6 +4688,14 @@ You can enable the DuckDuckGo website icon service in the security section of th Url Адрес + + Could not load key file. + Грешка при зареждане на файл с ключ. + + + Could not open remote database. Password or key file may be incorrect. + Грешка при отваряне на отдалечено хранилище. Паролата или файлът с ключ вероятно са грешни. + ImportWizardPageSelect @@ -4329,7 +4713,7 @@ You can enable the DuckDuckGo website icon service in the security section of th Key File: - Файл-ключ: + Файл с ключ: Browse… @@ -4393,7 +4777,7 @@ You can enable the DuckDuckGo website icon service in the security section of th Select key file - Избор на файл-ключ + Избор на файл с ключ Comma Separated Values @@ -4415,6 +4799,49 @@ You can enable the DuckDuckGo website icon service in the security section of th KeePass1 Database Хранилище на KeePass 1 + + Proton Pass (.json) + Proton Pass (.json) + + + Proton Pass JSON Export + Изнесен JSON от Proton Pass + + + Temporary Database + Временно хранилище + + + Command: + Команда: + + + e.g.: "sftp user@hostname" or "scp user@hostname:DatabaseOnRemote.kdbx {TEMP_DATABASE}" + напр.: „sftp user@hostname“ или „scp user@hostname:отдалечено-хранилище.kdbx {TEMP_DATABASE}“ + + + Input: + Въвеждане: + + + e.g.: +get DatabaseOnRemote.kdbx {TEMP_DATABASE} +exit +--- +{TEMP_DATABASE} is used as placeholder to store the database in a temporary location +The command has to exit. In case of `sftp` as last commend `exit` has to be sent + + напр.: +get отдалечено-хранилище.kdbx {TEMP_DATABASE} +exit +--- +Низът {TEMP_DATABASE} се използва за заместител на временното местоположение на хранилището +Командата трябва да завърши. В случая на `sftp` последната изпратена команда трябва да бъде `exit` + + + Remote Database (.kdbx) + Отдалечено хранилище (.kdbx) + KMessageWidget @@ -4854,7 +5281,7 @@ Line %2, column %3 KeePass1Reader Unable to read keyfile. - Файлът-ключ не може да бъде прочетен. + Файлът с ключ не може да бъде прочетен. Not a KeePass database. @@ -5556,12 +5983,6 @@ This version is not meant for production use. Expect some bugs and minor issues, this version is meant for testing purposes. ЗАБЕЛЕЖКА: Използвате предварително издание на KeePassXC! Очаквайте дефекти и несъществени проблеми, изданието е предназначено за изпитателни цели. - - - WARNING: Your Qt version may cause KeePassXC to crash with an On-Screen Keyboard. -We recommend you use the AppImage available on our downloads page. - ВНИМАНИЕ: Използваното издание на Qt може да доведе до срив на KeePassXC при работа с екранна клавиатура! -Препоръчваме да използвате AppImage, достъпен от страницата за изтегляне. No Tags @@ -5635,6 +6056,10 @@ We recommend you use the AppImage available on our downloads page. Import Passkey Внасяне на Passkey + + Remote S&ync… + Отдалечено &синхронизиране… + Quit Application Излиза от приложението @@ -5739,6 +6164,10 @@ We recommend you use the AppImage available on our downloads page. Show Password Generator Показва екрана за създаване на пароли + + Remove Passkey From Entry + Премахване на passkey от запис + Perform Auto-Type: {USERNAME} Извършва автоматично въвеждане: {USERNAME} @@ -5883,6 +6312,34 @@ We recommend you use the AppImage available on our downloads page. Toggle Allow Screen Capture Превключва разрешението за правене на екранни снимки + + Show Group Panel + Показване на панела „Група“ + + + Toggle Show Group Panel + Превключване на панела „Група“ + + + Setup Remote Sync… + Настройка на отдалеч. синхронизиране… + + + Password Generator + Създаване на парола + + + E&xpire Entry… + Прекратяване на &давността… + + + Clear SSH Agent + Изчистване на агента на SSH + + + Clear all identities in ssh-agent + Изчистване на самоличностите в ssh-agent + ManageDatabase @@ -6015,7 +6472,7 @@ We recommend you use the AppImage available on our downloads page. NewDatabaseWizardPageEncryption Encryption Settings - Настройки на шифроване + Настройки на шифроването Here you can adjust the database encryption settings. Don't worry, you can change them later in the database settings. @@ -6033,6 +6490,25 @@ We recommend you use the AppImage available on our downloads page. Въведете име и незадължително описание на новото хранилище: + + NewEntryAttachmentsDialog + + Attachment name cannot be empty + Името на прикачения файл не може да е празно + + + Attachment with the same name already exists + Прикачен файл със същото име вече съществува + + + Save attachment + Запазване + + + New entry attachment + Прикачен файл към нов запис + + NixUtils @@ -6220,6 +6696,10 @@ We recommend you use the AppImage available on our downloads page. Unexpected EOF when writing private key Неочакван край на файла при записване на частен ключ + + (encrypted) + (шифровано) + OpenSSHKeyGenDialog @@ -6268,7 +6748,7 @@ We recommend you use the AppImage available on our downloads page. Export the following passkey entries. - + Изнасяне на следните записи на passkey. @@ -6342,15 +6822,15 @@ Do you want to overwrite it? Import the following passkey: - + Внасяне на следния passkey: Import the following passkey to this entry: - + Внасяне на следния passkey в този запис: Default passkeys group (Imported Passkeys) - + Подразбирана група за passkeys (Внесени passkeys) @@ -6373,25 +6853,27 @@ Do you want to overwrite it? Open passkey file - + Отваряне на файл с passkey Cannot import passkey - + Грешка при внасяне на passkey Cannot import passkey file "%1". Data is missing. - + Грешка при внасяне на файл с passkey „%1“. Липсват данни. Cannot import passkey file "%1". The following data is missing: %2 - + Грешка при внасяне на файл с passkey „%1“. +Следните данни липсват: +%2 Cannot import passkey file "%1". Private key is missing or malformed. - + Грешка при внасяне на файл с passkey „%1“. Липсва / повреден частен ключ @@ -6572,10 +7054,6 @@ The following data is missing: Also choose from: Допълнителни знаци: - - Excluded characters: "0", "1", "l", "I", "O", "|", "﹒" - Изключени знаци: "0", "1", "l", "I", "O", "|", "﹒" - Exclude look-alike characters Изключване на еднакво изглеждащите знаци @@ -6600,10 +7078,6 @@ The following data is missing: Word Count: Брой думи: - - Character Count: - Брой знаци: - Word Case: Регистър на думите: @@ -6616,10 +7090,6 @@ The following data is missing: Add custom wordlist Добавяне на потребителски списък с думи - - character - знак - Close Затваряне @@ -6726,6 +7196,22 @@ Do you want to overwrite it? Special Characters Специални знаци + + passwordLength + passwordLength + + + Characters: %1 + Знаци: %1 + + + MIXED case + Смесване на регистри + + + Excluded characters: "0", "1", "l", "I", "O", "|", "﹒", "B", "8", "G", "6" + Изключени знаци: "0", "1", "l", "I", "O", "|", "﹒", "B", "8", "G", "6" + PasswordWidget @@ -6793,6 +7279,21 @@ Do you want to overwrite it? Натиснете &Табулатор между знаците + + PreviewEntryAttachmentsDialog + + Preview entry attachment + Преглед на прикачен файл към запис + + + No preview available + Не е възможен преглед + + + Image format not supported + Този вид изображения не се поддържат + + QMessageBox @@ -6840,7 +7341,7 @@ Do you want to overwrite it? QObject Database not opened - Хранилището не е отворено + Хранилището не е отключено Database hash not available @@ -7471,10 +7972,6 @@ Do you want to overwrite it? Invalid word count %1 Неприемлив брой думи %1 - - The word list is too small (< 1000 items) - Списъкът с думи е твърде къс (< 1000 елемента) - Title for the entry. Заглавие на записа. @@ -7619,10 +8116,6 @@ Do you want to overwrite it? Exit interactive mode. Излизане от интерактивен режим. - - Format to use when exporting. Available choices are 'xml' or 'csv'. Defaults to 'xml'. - Формат при изнасяне. Възможностите са „xml“ и „csv“. По подразбиране е „xml“. - Exports the content of a database to standard output in the specified format. Изнася съдържанието на хранилището към стандартния изход в указания формат. @@ -8052,7 +8545,7 @@ Please consider generating a new key file. Password expiry was %1 - Давността на паролата е до %1 + Давността на паролата е била до %1 Password expires on %1 @@ -8060,7 +8553,7 @@ Please consider generating a new key file. Password is about to expire - Давността на паролата скоро ще изтече + Давността на паролата изтича Password expires in %1 day(s) @@ -8068,7 +8561,7 @@ Please consider generating a new key file. Password will expire soon - Давността на паролата ще изтече скоро + Давността на паролата изтича Version %1 @@ -8210,18 +8703,6 @@ Kernel: %3 %4 file empty празен файл - - malformed string - повреден низ - - - missing closing quote - липсваща затваряща кавичка - - - %1: (row, col) %2,%3 - %1: (ред, колона) %2,%3 - AES 256-bit AES 256 разряден @@ -8410,11 +8891,11 @@ Kernel: %3 %4 KeePassXC is not running. No open database to lock - KeePassXC не работи. Няма отворено хранилище, което да бъде зключено + KeePassXC не работи. Няма отключено хранилище, което да бъде заключено Fatal error while testing the cryptographic functions. - Фатална грешка при изпитване на криптографските функции. + Фатална грешка при проверяване на криптографските функции. KeePassXC - Error @@ -8522,7 +9003,7 @@ This option is deprecated, use --set-key-file instead. Could not read key in keyring - Ключ не може да бъде прочетен от ключодържател + Ключ не може да бъде прочетен в ключодържателя AES decrypt failed @@ -8667,12 +9148,88 @@ This option is deprecated, use --set-key-file instead. Клавишни комбинации - Unsupported KDF type, cannot decrypt json file - Неподдържан вид на ФИК, файлът с JSON не може да бъде разшифрован + Unknown passkeys error + Неочаквана грешка на passkey - Unknown passkeys error - + Invalid KDF iterations, cannot decrypt json file + Неподдържан брой преобразувания с ФИК, файлът с JSON не може да бъде разшифрован + + + Unsupported format, ensure your Bitwarden export is password-protected + Неподдържан формат, уверете се, че изнесеното от Bitwarden е защитено с парола + + + Only PBKDF and Argon2 are supported, cannot decrypt json file + Поддържат се само PBKDF и Argon2, файлът с JSON не може да бъде разшифрован + + + Reset Shortcuts + Нулиране на клавишни комбинации + + + Double click an action to change its shortcut + За да промените клавишната комбинация щракнете двукратно върху желаното действие. + + + Filter... + Филтър… + + + Shortcut Conflict + Конфликт на клавишни комбинации + + + Shortcut %1 conflicts with '%2'. Overwrite shortcut? + Комбинацията %1 е в конфликт с „%2“. Презаписване на клавишната комбинация? + + + Cannot generate valid passphrases because the wordlist is too short + Не може да бъде създадена приемлива парола, защото списъкът с думи е твърде кратък. + + + Encrypted files are not supported. + Не се поддържат шифровани файлове. + + + Proton Pass Import + Внасяне от Proton Pass + + + Delete plugin data? + Изтриване на данни от разширението? + + + Delete plugin data from Entry(s)? + Премахване на информация от добавката от запис?Премахване на информация от добавката от записи? + + + Passkey + Passkey + + + Format to use when exporting. Available choices are 'xml', 'csv' or 'html'. Defaults to 'xml'. + Формат при изнасяне. Възможностите са „xml“, „csv“ и „html“ . По подразбиране е „xml“. + + + start minimized to the system tray + стартиране скрито в областта за известия + + + malformed string, possible unescaped delimiter + не добре форматиран низ вероятно има разделител без избягващ знак + + + missing closing delimiter + липсващ затварящ разделител + + + %1, row: %2, column: %3 + %1, ред: %2, колона: %3 + + + Tags + Етикети @@ -8709,6 +9266,37 @@ This option is deprecated, use --set-key-file instead. Вътрешна грешка на zlib: + + RemoteHandler + + Command `%1` did not finish in time. Process was killed. + Командата `%1` не завърши навреме. Процесът ѝ е спрян. + + + Failed to upload merged database. Command `%1` did not finish in time. Process was killed. + Грешка при качване на слятото хранилище. Командата `%1` не завърши навреме. Процесът ѝ е спрян. + + + Invalid download parameters provided. + Подадени са недействителни параметри за изтеглянето. + + + Command `%1` failed to download database. + Командата `%1` успя да изтегли хранилище. + + + Invalid database pointer or upload parameters provided. + Недействителен указател към хранилище или подадени недействителни параметри за качването. + + + Command `%1` exited with status code: %2 + Командата `%1` завърши с код на състоянието: %2 + + + Failed to upload merged database. Command `%1` exited with status code: %2 + Грешка при качване на слятото хранилище. Командата `%1` завърши с код на състоянието: %2 + + ReportsWidgetBrowserStatistics @@ -8775,6 +9363,10 @@ This option is deprecated, use --set-key-file instead. Exclude from reports Изключване от отчети + + Expire Entry(s)… + Прекратяване на давносттаПрекратяване на давността + Only show entries that have a URL Показване само на записи с адреси @@ -8789,38 +9381,35 @@ This option is deprecated, use --set-key-file instead. (Expired) - (Изтекла давност) + (изтекла давност) + + + Delete plugin data from Entry(s)… + Премахване на информация от добавката от запис…Премахване на информация от добавката от записи… ReportsWidgetHealthcheck - Hover over reason to show additional details. Double-click entries to edit. - За подробности, задръжте показалеца на мишката върху причината. За да промените запис, щракнете двукратно върху него. + Show expired entries + Показване на записи с изтекла давност - Bad - Password quality - Много лоша + (Expired) + (изтекла давност) + + + Hover over reason to show additional details. Double-click entries to edit. + За подробности, задръжте показалеца на мишката върху причината. За да промените запис, щракнете двукратно върху него. Bad — password must be changed Много лоша — паролата трябва да бъде променена - - Poor - Password quality - Лоша - Poor — password should be changed Лоша — добре е паролата да бъде променена - - Weak - Password quality - Слаба - Weak — consider changing the password Слаба — помислете за промяна на паролата @@ -8869,18 +9458,14 @@ This option is deprecated, use --set-key-file instead. Exclude from reports Изключване от отчети - - Show expired entries - Показване на записи с изтекла давност + + Expire Entry(s)… + Прекратяване на давносттаПрекратяване на давността Show entries that have been excluded from reports Показване и на изключените от отчети записи - - (Expired) - (Изтекла давност) - ReportsWidgetHibp @@ -8976,6 +9561,10 @@ This option is deprecated, use --set-key-file instead. Exclude from reports Изключване от отчети + + Expire Entry(s)… + Прекратяване на давносттаПрекратяване на давността + ReportsWidgetPasskeys @@ -9025,7 +9614,7 @@ This option is deprecated, use --set-key-file instead. (Expired) - (Изтекла давност) + (изтекла давност) Export Confirmation @@ -9037,11 +9626,11 @@ This option is deprecated, use --set-key-file instead. Please wait, list of entries with passkeys is being updated… - + Изчакайте, списъкът със записи с passkeys се обновява… No entries with passkeys. - + Липсват записи с passkeys. @@ -9217,6 +9806,14 @@ This option is deprecated, use --set-key-file instead. No agent running, cannot list identities. Няма работещ агент, самоличностите не могат да бъдат изброени. + + Failed to remove all SSH identities from agent. + Грешка при изчистване на самоличностите от ssh-agent. + + + All SSH identities removed from agent. + Самоличностите са изчистени от агента на SSH. + SearchHelpWidget @@ -9502,29 +10099,6 @@ This option is deprecated, use --set-key-file instead. Изнасяне в %1 - - ShortcutSettingsWidget - - Double click an action to change its shortcut - За да промените клавишната комбинация щракнете двукратно върху желаното действие. - - - Shortcut Conflict - Конфликт на клавишни комбинации - - - Filter... - Филтър… - - - Shortcut %1 conflicts with '%2'. Overwrite shortcut? - Комбинацията %1 е в конфликт с „%2“. Презаписване на клавишната комбинация? - - - Reset Shortcuts - Нулиране на клавишни комбинации - - TagModel @@ -9813,14 +10387,18 @@ Example: JBSWY3DPEHPK3PXP No hardware keys detected Не са открити хардуерни ключове - - <p>If you own a <a href="https://www.yubico.com/">YubiKey</a> or <a href="https://onlykey.io">OnlyKey</a>, you can use it for additional security.</p><p>The key requires one of its slots to be programmed as <a href="https://docs.yubico.com/yesdk/users-manual/application-otp/challenge-response.html">HMAC-SHA1 Challenge-Response</a>.</p> - <p>Ако разполагате с ключ като <a href="https://www.yubico.com/">YubiKey</a> или <a href="https://onlykey.io">OnlyKey</a>, можете да го използвате като допълнителна защита.</p><p> За целта, една от позициите на ключа трябва да е настроена като <a href="https://docs.yubico.com/yesdk/users-manual/application-otp/challenge-response.html">Предизвикване-отговор HMAC-SHA1</a>.</p> - Refresh hardware keys Презареждане на хардуерните ключове + + <p>If you own a <a href="https://www.yubico.com/">YubiKey</a> or <a href="https://onlykey.io">OnlyKey</a>, you can use it for additional security.</p><p>The key requires one of its slots to be programmed with <a href="https://keepassxc.org/docs/#faq-yubikey-howto">Challenge-Response</a>.</p> + <p>Ако разполагате със защитно устройство като <a href="https://www.yubico.com/">YubiKey</a> или <a href="https://onlykey.io">OnlyKey</a>, можете да го използвате като допълнителна защита.</p><p>За целта, една от позициите на ключа трябва да е настроена като <a href="https://keepassxc.org/docs/#faq-yubikey-howto">Предизвикване-отговор</a>.</p> + + + Hardware keys found, but no slots are configured + Открити са хардуерни ключове, но без настроени слотове. + YubiKeyInterfacePCSC diff --git a/share/translations/keepassxc_ca.ts b/share/translations/keepassxc_ca.ts index 99519a99e..8d2a094c2 100644 --- a/share/translations/keepassxc_ca.ts +++ b/share/translations/keepassxc_ca.ts @@ -11,7 +11,7 @@ Report bugs at: <a href="https://github.com/keepassxreboot/keepassxc/issues" style="text-decoration: underline;">https://github.com</a> - Informeu d'errors a: <a href="https://github.com/keepassxreboot/keepassxc/issues" style="text-decoration: underline;">https://github.com</a> + Reporteu errors a: <a href="https://github.com/keepassxreboot/keepassxc/issues" style="text-decoration: underline;">https://github.com</a> KeePassXC is distributed under the terms of the GNU General Public License (GPL) version 2 or (at your option) version 3. @@ -50,7 +50,7 @@ AccessControlDialog KeePassXC - Access Request - KeePassXC - Sol·licitud d'accés + Non-existing/inaccessible executable path. Please double-check the client is legit. @@ -78,7 +78,7 @@ Details - Detalls + Remember @@ -94,18 +94,18 @@ Deny All && Future - Denegar-ho tot & Futur + Allow All && &Future - Permet-ho tot & Futur + AccessControlDialog::DenyButton Deny for this program - Denega per a aquest programa + @@ -116,7 +116,7 @@ Use Pageant - Usa Pageant + Use OpenSSH @@ -124,7 +124,7 @@ SSH_AUTH_SOCK override - SSH_AUTH_SOCK override + SSH_AUTH_SOCK value @@ -140,7 +140,7 @@ SSH_SK_PROVIDER override - SSH_SK_PROVIDER override + No SSH Agent socket available. Either make sure SSH_AUTH_SOCK environment variable exists or set an override. @@ -150,16 +150,12 @@ SSH Agent connection is working! - - Use both agents - Usa ambdós agents - ApplicationSettingsWidget Application Settings - Paràmetres de l'aplicació + Configuració de l'aplicació General @@ -225,10 +221,6 @@ Select backup storage directory - - This setting cannot be enabled when minimize on unlock is enabled. - - ApplicationSettingsWidgetGeneral @@ -278,12 +270,12 @@ On database unlock, show entries that - Al desbloquejar la base de dades, mostra les entrades que + have expired On database unlock, show entries that... - ha caducat + days @@ -414,7 +406,7 @@ Use monospaced font for notes - Fer servir fonts monoespaiada per les notes + Usa lletra monoespaiada per a les notes Minimize instead of app exit @@ -497,14 +489,6 @@ Remember last typed entry for: - - recent files - fitxers recents - - - Show passwords in color - - ApplicationSettingsWidgetSecurity @@ -603,7 +587,7 @@ Auto-Type Error - Error de tecleig automàtic + Permission Required @@ -619,7 +603,7 @@ Invalid entry provided - Entrada proporcionada no vàlida + Bracket imbalance detected, found extra { or } @@ -654,10 +638,6 @@ Invalid placeholder: %1 - - Entry does not have attribute for PICKCHARS: %1 - - AutoTypeAssociationsModel @@ -705,7 +685,7 @@ Sequence aborted: Caps Lock is on - Seqüència avortada: el bloqueig de majúscules està activat + Sequence aborted: Modifier keys held by user @@ -737,11 +717,11 @@ Ctrl+4 - Use Virtual Keyboard (Windows Only)</p> Search all open databases - Cerca totes les bases de dades obertes + Search… - Cerca... + Type Sequence @@ -765,19 +745,19 @@ Ctrl+4 - Use Virtual Keyboard (Windows Only)</p> Copy Username - Copia el nom d'usuari + Copy Password - Copia la contrasenya + Copy TOTP - Copia TOTP + Use Virtual Keyboard - Utilitza el teclat virtual + @@ -804,11 +784,11 @@ Ctrl+4 - Use Virtual Keyboard (Windows Only)</p> Allow Selected - Permet la selecció + Permet els seleccionats Deny All - Denegar tot + Denega-ho tot Disable for this site @@ -1095,7 +1075,7 @@ Would you like to migrate your existing settings now? Browse… Button for opening file dialog - Explora... + Use a custom browser configuration location: @@ -1429,6 +1409,10 @@ Còpia de seguretat de la base de dades situada a %2 Key File: Fitxer clau: + + <p>In addition to a password, you can use a secret file to enhance the security of your database. This file can be generated in your database's security settings.</p><p>This is <strong>not</strong> your *.kdbx database file!<br>If you do not have a key file, leave this field empty.</p><p>Click for more information…</p> + + Key file help @@ -1441,13 +1425,18 @@ Còpia de seguretat de la base de dades situada a %2 Hardware Key: Motxilla: + + <p>You can use a hardware security key such as a <strong>YubiKey</strong> or <strong>OnlyKey</strong> with slots configured for HMAC-SHA1.</p> +<p>Click for more information…</p> + + Hardware key help Ajuda de la motxilla Key file to unlock the database - Fitxer clau per desbloquejar la base de dades + Browse for key file @@ -1455,7 +1444,7 @@ Còpia de seguretat de la base de dades situada a %2 Browse… - Explora... + Refresh hardware tokens @@ -1467,7 +1456,7 @@ Còpia de seguretat de la base de dades situada a %2 Unlock Database - Desbloqueja la base de dades + Cancel @@ -1475,7 +1464,7 @@ Còpia de seguretat de la base de dades situada a %2 Unlock - Desbloqueja + Please present or touch your YubiKey to continue… @@ -1501,7 +1490,7 @@ We recommend you update your KeePassXC installation. Database unlock canceled. - Desbloqueig de la base de dades cancel·lat. + Unlock failed and no password given @@ -1575,15 +1564,6 @@ If you do not have a key file, please leave the field empty. Select hardware key… - - <p>In addition to a password, you can use a secret file to enhance the security of your database. This file can be generated in your database's security settings.</p><p>This is <strong>not</strong> your *.kdbx database file!<br>If you do not have a key file, leave this field empty.</p><p>Click for more information…</p> - - - - <p>You can use a hardware security key such as a <strong>YubiKey</strong> or <strong>OnlyKey</strong> with slots configured for HMAC-SHA1.</p> -<p>Click for more information…</p> - - DatabaseSettingWidgetMetaData @@ -1608,7 +1588,7 @@ If you do not have a key file, please leave the field empty. Database Credentials - Credencials de la base de dades + Encryption Settings @@ -1663,7 +1643,7 @@ If you do not have a key file, please leave the field empty. Remove - Suprimiu + Suprimeix Delete the selected key? @@ -2223,21 +2203,13 @@ This is definitely a bug, please report it to the developers. Database tab name modifier %1 [bloquejat] - - Export database to XML file - - - - XML file - - - - Writing the XML file failed - - DatabaseWidget + + Database Tags + + Searching… @@ -2284,7 +2256,7 @@ This is definitely a bug, please report it to the developers. Expired entries - Entrades caducades + No current database. @@ -2404,22 +2376,6 @@ Voleu deshabilitar el desat segur i provar-ho un altre cop? Entries expiring within %1 day(s) - - Searches and Tags - - - - Enter a unique name or overwrite an existing search from the list: - - - - Save - Desa - - - Save Search - - EditEntryWidget @@ -2556,6 +2512,10 @@ Would you like to correct it? Hide Oculta + + Tomorrow + Demà + %n week(s) % n setmana/es%n setmana/es @@ -2568,10 +2528,6 @@ Would you like to correct it? %n year(s) % n any/s%n any/s - - %n hour(s) - - EditEntryWidgetAdvanced @@ -2959,7 +2915,7 @@ Would you like to correct it? Browse… Button for opening file dialog - Explora... + Attachment @@ -3087,14 +3043,6 @@ Would you like to correct it? Do not use HTTP Auth toggle for this and sub groups - - Omit WWW subdomain from matching: - - - - Omit WWW subdomain from matching toggle for this and sub groups - - EditGroupWidgetKeeShare @@ -3128,7 +3076,7 @@ Would you like to correct it? Browse… - Explora... + Clear fields @@ -3676,10 +3624,6 @@ Error: %1 Auto-Type Compleció automàtica - - Tags - - EntryModel @@ -3786,14 +3730,14 @@ Error: %1 Has TOTP - Disposa de TOTP + EntryPreviewWidget Display current TOTP value - Mostra el valor actual de TOTP + Close @@ -3887,10 +3831,6 @@ Error: %1 Disabled Inhabilitat - - Double click to copy value - - EntryURLModel @@ -4808,7 +4748,7 @@ If this reoccurs, then your database file may be corrupt. Note: Do NOT use a file that may change as that will prevent you from unlocking your database. - Nota: NO utilitzeu un fitxer que pugui canviar, ja que us impedirà desbloquejar la base de dades. + Browse for key file @@ -4816,7 +4756,7 @@ If this reoccurs, then your database file may be corrupt. Browse… - Explora... + Old key file format @@ -5060,7 +5000,7 @@ Are you sure you want to continue with this file? Database &Reports… - Informes de la base de dades + Statistics, health check, etc. @@ -5132,11 +5072,11 @@ Are you sure you want to continue with this file? &Lock Database - B&loqueja la base de dades + Lock &All Databases - Bloqueja totes les bases de dades + &Title @@ -5200,11 +5140,11 @@ Are you sure you want to continue with this file? Show QR Code - Mostra el codi QR + Set up TOTP… - Configura el TOTP... + Copy &TOTP @@ -5252,7 +5192,7 @@ Are you sure you want to continue with this file? Save Database Backup… - Desa una còpia de seguretat... + Add key to SSH Agent @@ -5276,11 +5216,11 @@ Are you sure you want to continue with this file? Dark - Fosc + Classic (Platform-native) - Clàssic (natiu de la plataforma) + Show Toolbar @@ -5374,30 +5314,6 @@ We recommend you use the AppImage available on our downloads page. You must restart the application to apply this setting. Would you like to restart now? - - Tags - - - - No Tags - - - - %1 Entry(s) - - - - Copy Password and TOTP - Copia la contrasenya i el TOTP - - - &XML File… - - - - XML File… - - ManageDatabase @@ -5547,7 +5463,7 @@ We recommend you use the AppImage available on our downloads page. NewDatabaseWizardPageDatabaseKey Database Credentials - Credencials de la base de dades + A set of credentials known only to you that protects your database. @@ -5768,6 +5684,29 @@ We recommend you use the AppImage available on our downloads page. + + PasswordEdit + + Passwords do not match + + + + Passwords match so far + + + + Toggle Password (%1) + + + + Generate Password (%1) + + + + Warning: Caps Lock enabled! + + + PasswordEditWidget @@ -5946,6 +5885,10 @@ We recommend you use the AppImage available on our downloads page. Also choose from: + + Excluded characters: "0", "1", "l", "I", "O", "|", "﹒" + + Exclude look-alike characters Excloure caràcters d'aspecte semblant @@ -6095,57 +6038,6 @@ Do you want to overwrite it? Password quality Excel·lent - - Excluded characters: "0", "1", "l", "I", "O", "|", "﹒" - - - - - PasswordWidget - - Passwords do not match - - - - Passwords match so far - - - - Toggle Password (%1) - - - - Generate Password (%1) - - - - Warning: Caps Lock enabled! - - - - Quality: %1 - - - - Poor - Password quality - Pobre - - - Weak - Password quality - Feble - - - Good - Password quality - Bona - - - Excellent - Password quality - Excel·lent - PickcharsDialog @@ -6490,7 +6382,7 @@ Do you want to overwrite it? Copy the current TOTP to the clipboard (equivalent to "-a totp"). - Copia el TOTP actual al porta-retalls (equivalent a "-a totp"). + Must match only one entry, otherwise a list of possible matches is shown. @@ -6527,11 +6419,11 @@ Do you want to overwrite it? ERROR: Please specify one of --attribute or --totp, not both. - ERROR: Especifiqueu un, --atribut o --totp, no tots dos. + Entry with path %1 has no TOTP set up. - L'entrada amb la ruta %1 no té configurat TOTP. + ERROR: attribute %1 is ambiguous, it matches %2. @@ -7203,7 +7095,7 @@ Available commands: Show the entry's current TOTP. - Mostra el TOTP actual de l'entrada. + Show the protected attributes in clear text. @@ -7276,6 +7168,10 @@ Please consider generating a new key file. Invalid YubiKey serial %1 + + Please present or touch your YubiKey to continue… + + Enter password to encrypt database (optional): @@ -7423,7 +7319,7 @@ Nucli: %3 %4 Quick Unlock - Desbloqueig ràpid + Secret Service Integration @@ -7649,11 +7545,11 @@ Nucli: %3 %4 Browser Statistics - Estadístiques del navegador + Health Check - Informe de salut + HIBP @@ -7661,7 +7557,7 @@ Nucli: %3 %4 Statistics - Estadístiques + Unsupported key file version: %1 @@ -7693,7 +7589,7 @@ Nucli: %3 %4 lock all open databases - bloqueja totes les bases de dades obertes + key file of the database @@ -7709,11 +7605,11 @@ Nucli: %3 %4 Locked databases. - Bases de dades bloquejades. + Database failed to lock. - La base de dades no s'ha pogut bloquejar. + Another instance of KeePassXC is already running. @@ -7753,67 +7649,6 @@ Nucli: %3 %4 Failed to sign challenge using Windows Hello. - - Please present or touch your YubiKey to continue. - - - - Show all the attributes of the entry. - - - - Edit a database. - - - - Could not change the database key. - - - - Database was not modified. - - - - Successfully edited the database. - - - - Loading the new key file failed: %1 - - - - Unset the password for the database. - - - - Unset the key file for the database. - - - - Cannot use %1 and %2 at the same time. - - - - Cannot remove all the keys from a database. - - - - Cannot remove password: The database does not have a password. - - - - Cannot remove file key: The database does not have a file key. - - - - Found unexpected Key type %1 - - - - Set the key file for the database. -This options is deprecated, use --set-key-file instead. - - QtIOCompressor @@ -8361,10 +8196,6 @@ This options is deprecated, use --set-key-file instead. Limit search to selected group Limitar la cerca al grup seleccionat - - Save Search - - SettingsClientModel @@ -8577,39 +8408,16 @@ This options is deprecated, use --set-key-file instead. TagModel + + All + + Expired - Caducades + Weak Passwords - Contrasenyes febles - - - All Entries - - - - Clear Search - - - - - TagView - - Remove Search - - - - Remove Tag - - - - Confirm Remove Tag - - - - Remove tag "%1" from all entries in this database? @@ -8641,7 +8449,7 @@ This options is deprecated, use --set-key-file instead. There was an error creating the QR code. - Hi hagut un error creant el codi QR + Closing in %1 seconds. @@ -8709,7 +8517,7 @@ This options is deprecated, use --set-key-file instead. Invalid TOTP Secret - Secret de TOTP no vàlid + You have entered an invalid secret key. The key must be in Base32 format. @@ -8718,7 +8526,7 @@ Example: JBSWY3DPEHPK3PXP Confirm Remove TOTP Settings - Confirma l'eliminació de la configuració de TOTP + Are you sure you want to delete TOTP settings for this entry? diff --git a/share/translations/keepassxc_cs.ts b/share/translations/keepassxc_cs.ts index a18051647..a594c8eb2 100644 --- a/share/translations/keepassxc_cs.ts +++ b/share/translations/keepassxc_cs.ts @@ -217,18 +217,50 @@ You must restart the application to set the new language. Would you like to restart now? Aby se změna jazyka projevila, je třeba aplikaci restartovat. Chcete to provést nyní? - - Reset Settings? - Vrátit nastavení do výchozích hodnot? - - - Are you sure you want to reset all general and security settings to default? - Opravdu chcete vrátit veškerá obecná nastavení a nastavení zabezpečení do výchozích hodnot? - Select backup storage directory Vybrat složku pro ukládání záloh + + Confirm Reset + + + + Are you sure you want to reset all settings to default? + + + + Import KeePassXC Settings + + + + Failed to import settings from %1, not a valid settings file. + + + + Export KeePassXC Settings + + + + Small + + + + Normal + + + + Medium + + + + Large + + + + Custom + + ApplicationSettingsWidgetGeneral @@ -280,25 +312,6 @@ Include beta releases when checking for updates Při zjišťování případných aktualizací brát v potaz i vývojové testovací verze - - On database unlock, show entries that - Při odemknutí databáze zobrazovat položky kterým - - - have expired - On database unlock, show entries that... - platnost skončila - - - days - On database unlock, show entries that will expire within %1 days - dnů - - - will expire within - On database unlock, show entries that... - skončí platnost za - File Management Správa souboru @@ -323,22 +336,10 @@ Backup database file before saving Před uložením zazálohovat databázový soubor - - Backup destination - Cíl zálohy - - - Specifies the database backup file location. Occurrences of "{DB_FILENAME}" are replaced with the filename of the saved database without extension. {TIME:<format>} is replaced with the backup time, see https://doc.qt.io/qt-5/qdatetime.html#toString. <format> defaults to format string "dd_MM_yyyy_hh-mm-ss". - - {DB_FILENAME}.old.kdbx {NAZEV_SOUBOR_S_DB}.stare.kdbx - - Choose... - Zvolit - Use alternative saving method (may solve problems with Dropbox, Google Drive, GVFS, etc.) Použít alternativní metodu ukládání (může vyřešit problémy s se službami Dropbox, Google Drive, vrstvami typu GVFS, atp.) @@ -505,6 +506,71 @@ Remember last typed entry for: Pamatovat si naposledy zadanou položku po dobu: + + On database unlock, show entries that will expire within + + + + On database unlock, show entries that will expire within + + + + days + number of days warning for password expiration + dnů + + + Destination format: + + + + <html><head/><body><p><span style=" font-weight:600;">{DB_FILENAME}</span> is replaced with the filename of the saved database without extension</p><p><span style=" font-weight:600;">{TIME:&lt;format&gt;}</span> is replaced with the specified time format (default: dd_MM_yyyy_hh-mm-ss)</p><p>See the User Guide for more details</p></body></html> + + + + Choose folder... + + + + Show confirmation before moving entries to recycle bin + + + + Copy data on double clicking field in entry view + + + + Show toolbar + Zobrazovat lištu nástrojů + + + Show the menu bar by pressing the Alt key + + + + Show menubar + + + + Import settings… + + + + Export settings… + + + + Open browser on double clicking URL field in entry view + + + + Font size: + + + + Font size selection + + ApplicationSettingsWidgetSecurity @@ -570,18 +636,6 @@ Hide passwords in the entry preview panel Skrýt hesla v panelu náhledu položky - - Hide entry notes by default - Skrývat ve výchozím stavu poznámky k položkám - - - Move entries to recycle bin without confirmation - Přesunout záznamy do Koše? - - - Enable double click to copy the username/password entry columns - Zapnout kopírování dvojklikem na sloupce s uživatelským jménem / heslem - Privacy Soukromí @@ -594,6 +648,18 @@ Hide TOTP in the entry preview panel Skrýt TOTP v panelu náhledu položky + + Lock databases when switching user + + + + Lock Options + + + + Hide notes in the entry preview panel + + AutoType @@ -641,20 +707,6 @@ Entry does not have attribute for PICKCHARS: %1 Záznam nemá atribut pro PICKCHARS: %1 - - Invalid conversion type: %1 - Neplatný typ převodu: %1 - - - Invalid conversion syntax: %1 - Neplatná syntaxe převodu: %1 - - - Invalid regular expression syntax %1 -%2 - Neplatná forma zápisu regulárního výrahu %1 -%2 - Invalid placeholder: %1 Neplatná výplň: %1 @@ -714,7 +766,7 @@ Trying to send invalid keyboard symbol. - + Pokus o odeslání neplatného symbolu. @@ -853,19 +905,19 @@ Vyberte databázi, do které chcete přihlašovací údaje uložit. Authenticate - + Ověřit Register new - + Zaregistrovat nové Register - + Registrovat Timeout in <b>%n</b> seconds... - + Časový limit v <b>%n</b> sekundách...Časový limit v <b>%n</b> sekundách...Časový limit v <b>%n</b> sekundách...Časový limit vyprší za <b>%n</b> sekundy... Relying Party: %1 @@ -873,7 +925,7 @@ Vyberte databázi, do které chcete přihlašovací údaje uložit. Username: %1 - + Uživatelské jméno: %1 KeePassXC - Passkey credentials @@ -886,11 +938,12 @@ Vyberte databázi, do které chcete přihlašovací údaje uložit. Existing passkey found. Do you want to register a new passkey for: - + Byl nalezen existující přístupový klíč. +Chcete uložit nový přístupový klíč pro: Select the existing passkey and press Update to replace it. - + Vyberte existující přístupový klíč a stisknutím Aktualizovat jej nahraďte. Authenticate passkey credentials for: @@ -898,7 +951,7 @@ Do you want to register a new passkey for: Do you want to register a passkey for: - + Chcete uložit přístupový klíč pro: @@ -951,7 +1004,8 @@ Opravdu chcete tuto položku smazat? KeePassXC - Create a new group - + KeePassXC - Vytvořit novou skupinu + Disable @@ -996,7 +1050,7 @@ Do you want to overwrite the passkey in %1 - %2? Register - + Registrovat @@ -1017,10 +1071,6 @@ Do you want to overwrite the passkey in %1 - %2? General Obecné - - Browsers installed as snaps are currently not supported. - Prohlížeče, nainstalované formou snap balíčků, zatím nejsou podporované. - Enable integration for these browsers: Zapnout propojení pro tyto prohlížeče: @@ -1192,18 +1242,6 @@ Do you want to overwrite the passkey in %1 - %2? Custom extension ID Identif. uživatelsky určeného rozšíření - - Due to Snap sandboxing, you must run a script to enable browser integration.<br />You can obtain this script from %1 - Z důvodu, že software ze Snap balíčku je provozován v ohraničeném prostředí, je třeba spustit skript, který zapíná napojení na webový prohlížeč. <br />Tento skript je možné získat z %1 - - - KeePassXC-Browser is needed for the browser integration to work. <br />Download it for %1 and %2 and %3. %4 - Aby fungovalo napojení na prohlížeč, je třeba KeePassXC. <br /> Stáhnete ho pro %1 a %2 a %3. %4 - - - Please see special instructions for browser extension use below - Níže si přečtěte konkrétní pokyny pro rozšíření do webového prohlížeče - Executable Files Spustitelné soubory @@ -1252,6 +1290,14 @@ Do you want to overwrite the passkey in %1 - %2? Allow using localhost with passkeys + + KeePassXC-Browser is needed for the browser integration to work. <br />Download it for %1 and %2 and %3. + + + + Browsers installed using Snap or Flatpak are not supported with exception to Firefox installed using Snap. + + CloneDialog @@ -1394,6 +1440,19 @@ Do you want to overwrite the passkey in %1 - %2? Imported from CSV file: %1 + + No Title Selected + + + + No title column was selected, entries will be hard to tell apart. +Are you sure you want to import? + + + + Tags + Štítky + CsvParserModel @@ -1457,6 +1516,14 @@ Záložní databáze se nachází v %2 Recycle Bin Koš + + Database file read error. + + + + No file path was provided. + + DatabaseOpenDialog @@ -1597,50 +1664,58 @@ Abyste tomu, aby se tato chyba objevovala, je třeba přejít do „Nastavení d Select Key File: - + Vyberte soubor klíče: <p>In addition to a password, you can use a secret file to enhance the security of your database. This file can be generated in your database's security settings.</p><p>This is <strong>not</strong> your *.kdbx database file!</p> + + Use hardware key [Serial: %1] + Použít hardwarový klíč [Serial: %1] + + + Use hardware key + Použít hardwarový klíč + + + Your database file is NOT a key file! +If you don't have a key file or don't know what that is, you don't have to select one. + Váš databázový soubor NENÍ klíčový soubor! +Pokud nemáte klíčový soubor nebo nevíte, co to je, nemusíte ho vybrat. + + + KeePassXC database file selected + Vybraný databázový soubor KeePassXC + + + The file you selected looks like a database file. +A database file is NOT a key file! + +Are you sure you want to continue with this file?. + Soubor, který jste vybrali, vypadá jako databázový soubor. +Databázový soubor NENÍ klíčový soubor! + +Opravdu chcete pokračovat s tímto souborem?. + + + No hardware keys found. + Nebyly nalezeny žádné hardwarové klíče. + + + Refresh Hardware Keys + Aktualizace hardwarových klíčů + Click to add a key file. <a href="#" style="text-decoration: underline">I have a key file</a> - + <a href="#" style="text-decoration: underline">Mám klíčový soubor</a> - Use hardware key [Serial: %1] - - - - Use hardware key - - - - Your database file is NOT a key file! -If you don't have a key file or don't know what that is, you don't have to select one. - - - - KeePassXC database file selected - - - - The file you selected looks like a database file. -A database file is NOT a key file! - -Are you sure you want to continue with this file?. - - - - No hardware keys found. - - - - Refresh Hardware Keys + Hardware keys found, but no slots are configured. @@ -1677,6 +1752,22 @@ Are you sure you want to continue with this file?. Maintenance Údržba + + KeeShare + KeeShare + + + Secret Service Integration + Zapnout napojení na Secret Service + + + Remote Sync + + + + Database Settings: %1 + + DatabaseSettingsWidgetBrowser @@ -1790,11 +1881,11 @@ Toto je nutné pouze v případě, že vaše databáze je kopií jiné a nefungu No keys found - + Nebyly nalezeny žádné klíče Removed keys from database - + Odstraněné klíče z databáze Removed permissions @@ -1802,7 +1893,7 @@ Toto je nutné pouze v případě, že vaše databáze je kopií jiné a nefungu No entry with permissions found! - + Nebyl nalezen žádný záznam s oprávnění! @@ -1848,11 +1939,11 @@ Opravdu chcete pokračovat bez hesla? Slabé heslo - You must enter a stronger password to protect your database. + This is a weak password! For better protection of your secrets, you should choose a stronger password. - This is a weak password! For better protection of your secrets, you should choose a stronger password. + The provided password does not meet the minimum quality requirement. @@ -2000,7 +2091,7 @@ Pokud tento počet ponecháte, vaše databáze nebude chráněna před útoky zk Basic - + Základní Advanced @@ -2147,6 +2238,50 @@ removed from the database. Autosave delay since last change checkbox + + Public Database Metadata + + + + Warning: the following settings are not encrypted. + + + + Display name: + + + + Publically visible display name used on the unlock dialog + + + + Database public display name + + + + Display color: + + + + Publically visible color used on the unlock dialog + + + + Database public display color chooser + + + + Clear + Vyčistit + + + Display icon: + + + + Select Database Icon + + DatabaseSettingsWidgetKeeShare @@ -2242,6 +2377,129 @@ removed from the database. Kolonka popis databáze + + DatabaseSettingsWidgetRemote + + Sync Commands + + + + Remove + Odebrat + + + Command Settings + + + + Name + Název + + + Save + Uložit + + + Download + + + + Command: + + + + Download command field + + + + e.g.: "sftp user@hostname" or "scp user@hostname:DatabaseOnRemote.kdbx {TEMP_DATABASE}" + + + + Input: + + + + Download input field + + + + Upload + + + + Upload command field + + + + e.g.: "sftp user@hostname" or "scp {TEMP_DATABASE} user@hostname:DatabaseOnRemote.kdbx" + + + + Upload input field + + + + Name cannot be empty. + + + + Test + + + + Download command cannot be empty. + + + + Download failed with error: %1 + + + + Download finished, but file %1 could not be found. + + + + Download successful. + + + + Save Remote Settings + + + + You have unsaved changes. Do you want to save them? + + + + e.g.: +get DatabaseOnRemote.kdbx {TEMP_DATABASE} +exit +--- +{TEMP_DATABASE} is used as placeholder to store the database in a temporary location +The command has to exit. In case of `sftp` as last command `exit` has to be sent + + + + + e.g.: +put {TEMP_DATABASE} DatabaseOnRemote.kdbx +exit +--- +{TEMP_DATABASE} is used as placeholder to store the database in a temporary location +The command has to exit. In case of `sftp` as last command `exit` has to be sent + + + + + Timeout: + + + + seconds + sekund + + DatabaseTabWidget @@ -2315,6 +2573,11 @@ Toto je nepochybně chyba, nahlaste ji prosím vývojářům. Database tab name modifier %1 [uzamčeno] + + %1 [Temporary] + Database tab name modifier + + DatabaseWidget @@ -2438,26 +2701,6 @@ Uložit změny? File has changed Soubor byl změněn - - The database file has changed. Do you want to load the changes? - Soubor s databází byl změněn. Načíst změny? - - - Merge Request - Požadavek na sloučení - - - The database file has changed and you have unsaved changes. -Do you want to merge your changes? - Databázový soubor byl změněn a máte neuložené změny. -Přejete si je zahrnout? - - - Could not open the new database file while attempting to autoreload. -Error: %1 - Nepodařilo se otevřít nový soubor s databází během pokusu o její opětovné načtení. -Chyba: %1 - Disable safe saves? Vypnout bezpečná ukládání? @@ -2509,6 +2752,86 @@ Vypnout bezpečné ukládání a zkusit to znovu? Database tab name modifier %1 [nová databáze] + + Remote Sync did not contain any download or upload commands. + + + + Remote sync '%1' completed successfully! + + + + Remote sync '%1' failed: %2 + + + + Error while saving database %1: %2 + + + + Downloading... + Stahování… + + + Uploading... + + + + Syncing... + + + + Remove passkey from entry + + + + Do you want to remove the passkey from this entry? + + + + The database file "%1" was modified externally + + + + Do you want to load the changes? + + + + Reload database + + + + Reloading database… + + + + Reload canceled + + + + Reload successful + + + + Reload pending user action… + + + + The database file "%1" was modified externally.<br>How would you like to proceed?<br><br>Merge all changes<br>Ignore the changes on disk until save<br>Discard unsaved changes + + + + The database file "%1" was modified externally.<br>How would you like to proceed?<br><br>Merge all changes then save<br>Overwrite the changes on disk<br>Discard unsaved changes + + + + Database file overwritten. + + + + Database file on disk cannot be unlocked with current credentials.<br>Enter new credentials and/or present hardware key to continue. + + EditEntryWidget @@ -2560,10 +2883,6 @@ Vypnout bezpečné ukládání a zkusit to znovu? n/a neaplikovatelné - - (encrypted) - (šifrováno) - Select private key Vybrat soukromou část klíče @@ -2666,6 +2985,10 @@ Chcete ji opravit? %n year(s) %n rok%n roky%n let%n roky + + Failed to decrypt SSH key, ensure password is correct. + + EditEntryWidgetAdvanced @@ -2837,18 +3160,10 @@ Chcete ji opravit? Skip Auto-Submit for this entry Přeskočit automatické odeslání pro tento záznam - - Only send this setting to the browser for HTTP Auth dialogs. If enabled, normal login forms will not show this entry for selection. - Toto nastavení posílat do prohlížeče pouze pro dialogy HTTP Auth. Pokud je zapnuto, běžné přihlašovací formuláře nezobrazí tuto položku pro výběr. - Use this entry only with HTTP Basic Auth Tuto položku použít pouze ve spojení se základním HTTP ověřováním se - - Do not send this setting to the browser for HTTP Auth dialogs. If enabled, HTTP Auth dialogs will not show this entry for selection. - - Do not use this entry with HTTP Basic Auth Tuto položku nepoužívat ve spojení se základním HTTP ověřováním se @@ -2873,6 +3188,14 @@ Chcete ji opravit? Additional URLs + + Only send this entry to the browser for HTTP Auth dialogs. If enabled, normal login forms will not show this entry for selection. + + + + Do not send this entry to the browser for HTTP Auth dialogs. If enabled, HTTP Auth dialogs will not show this entry for selection. + + EditEntryWidgetHistory @@ -3095,6 +3418,10 @@ Chcete ji opravit? seconds sekund + + Clear agent + + EditGroupWidget @@ -3537,6 +3864,24 @@ Dotčený zásuvný modul to může rozbít. %1 - Clone %1 – klon + + Passkey + + + + Invalid conversion type: %1 + Neplatný typ převodu: %1 + + + Invalid conversion syntax: %1 + Neplatná syntaxe převodu: %1 + + + Invalid regular expression syntax %1 +%2 + Neplatná forma zápisu regulárního výrahu %1 +%2 + EntryAttachments @@ -3545,6 +3890,21 @@ Dotčený zásuvný modul to může rozbít. Soubor „%1 se nedaří otevřít. + + EntryAttachmentsDialog + + Form + Formulář + + + File name + + + + File contents... + + + EntryAttachmentsModel @@ -3582,14 +3942,6 @@ Dotčený zásuvný modul to může rozbít. Remove Odebrat - - Rename selected attachment - Přejmenovat označenou přílohu - - - Rename - Přejmenovat - Open selected attachment Otevřít označenou přílohu @@ -3707,6 +4059,18 @@ Would you like to overwrite the existing attachment? Příloha „%1“ už existuje. Chcete stávající přílohu přepsat? + + New + + + + Preview + Náhled + + + Failed to preview an attachment: Attachment not found + + EntryAttributesModel @@ -3905,6 +4269,10 @@ Chcete stávající přílohu přepsat? Background Color + + Group Path + + EntryPreviewWidget @@ -4300,6 +4668,14 @@ Můžete zapnout službu pro stahování ikon z DuckDuckGo v sekci zabezpečení Url + + Could not load key file. + + + + Could not open remote database. Password or key file may be incorrect. + + ImportWizardPageSelect @@ -4403,6 +4779,44 @@ Můžete zapnout službu pro stahování ikon z DuckDuckGo v sekci zabezpečení KeePass1 Database + + Proton Pass (.json) + + + + Proton Pass JSON Export + + + + Temporary Database + + + + Command: + + + + e.g.: "sftp user@hostname" or "scp user@hostname:DatabaseOnRemote.kdbx {TEMP_DATABASE}" + + + + Input: + + + + e.g.: +get DatabaseOnRemote.kdbx {TEMP_DATABASE} +exit +--- +{TEMP_DATABASE} is used as placeholder to store the database in a temporary location +The command has to exit. In case of `sftp` as last commend `exit` has to be sent + + + + + Remote Database (.kdbx) + + KMessageWidget @@ -5543,12 +5957,6 @@ Tato verze není určena pro produkční použití. Expect some bugs and minor issues, this version is meant for testing purposes. UPOZORNĚNÍ: Používáte vývojové sestavení KeePassXC.0 Očekávejte chyby a drobné problémy, tato verze je určena pouze pro účely testování. - - - WARNING: Your Qt version may cause KeePassXC to crash with an On-Screen Keyboard. -We recommend you use the AppImage available on our downloads page. - VAROVÁNÍ: Vámi používaná verze Qt může způsobovat, že při použití klávesnice na obrazovce KeePassXC zhavaruje. -Doporučujeme použít AppImage, které je k dispozici v sekci stahování našich stránek. No Tags @@ -5622,6 +6030,10 @@ Doporučujeme použít AppImage, které je k dispozici v sekci stahování naši Import Passkey + + Remote S&ync… + + Quit Application @@ -5632,11 +6044,11 @@ Doporučujeme použít AppImage, které je k dispozici v sekci stahování naši Open Database - + Otevřít databázi Create Database - + Vytvořit databázi Merge From Database @@ -5726,6 +6138,10 @@ Doporučujeme použít AppImage, které je k dispozici v sekci stahování naši Show Password Generator + + Remove Passkey From Entry + + Perform Auto-Type: {USERNAME} @@ -5870,6 +6286,34 @@ Doporučujeme použít AppImage, které je k dispozici v sekci stahování naši Toggle Allow Screen Capture + + Show Group Panel + + + + Toggle Show Group Panel + + + + Setup Remote Sync… + + + + Password Generator + Vytváření hesel + + + E&xpire Entry… + + + + Clear SSH Agent + + + + Clear all identities in ssh-agent + + ManageDatabase @@ -6020,6 +6464,25 @@ Doporučujeme použít AppImage, které je k dispozici v sekci stahování naši Vyplňte zobrazovaný název a volitelný popis nové databáze: + + NewEntryAttachmentsDialog + + Attachment name cannot be empty + + + + Attachment with the same name already exists + + + + Save attachment + Uložit přílohu + + + New entry attachment + + + NixUtils @@ -6207,6 +6670,10 @@ Doporučujeme použít AppImage, které je k dispozici v sekci stahování naši Unexpected EOF when writing private key Neočekávaný konec souboru při zápisu soukromé části klíče + + (encrypted) + (šifrováno) + OpenSSHKeyGenDialog @@ -6291,7 +6758,7 @@ Do you want to overwrite it? Username: %1 - + Uživatelské jméno: %1 Group @@ -6557,10 +7024,6 @@ The following data is missing: Also choose from: Také zvolte z: - - Excluded characters: "0", "1", "l", "I", "O", "|", "﹒" - Vynechané znaky: „0“, „1“, „l“, „I“, „O“, „|“, „ . “ - Exclude look-alike characters Vynechat podobně vypadající znaky (předejití záměně) @@ -6585,10 +7048,6 @@ The following data is missing: Word Count: Počet slov: - - Character Count: - Počet znaků: - Word Case: Velikost písmen: @@ -6601,10 +7060,6 @@ The following data is missing: Add custom wordlist Přidat uživatelsky určený seznam slov - - character - znak - Close Zavřít @@ -6711,6 +7166,22 @@ Chcete ho přepsat? Special Characters Zvláštní znaky + + passwordLength + + + + Characters: %1 + + + + MIXED case + + + + Excluded characters: "0", "1", "l", "I", "O", "|", "﹒", "B", "8", "G", "6" + + PasswordWidget @@ -6778,6 +7249,21 @@ Chcete ho přepsat? Mezi znaky stisknout &tabulátor + + PreviewEntryAttachmentsDialog + + Preview entry attachment + + + + No preview available + + + + Image format not supported + + + QMessageBox @@ -7456,10 +7942,6 @@ Chcete ho přepsat? Invalid word count %1 Neplatný počet slov %1 - - The word list is too small (< 1000 items) - Seznam slov je příliš krátký (< 1000 položek) - Title for the entry. Titulek pro záznam. @@ -7604,10 +8086,6 @@ Chcete ho přepsat? Exit interactive mode. Opustit interaktivní režim. - - Format to use when exporting. Available choices are 'xml' or 'csv'. Defaults to 'xml'. - Formát který použít pro export. Možnosti jsou „xml“ nebo „csv“. Výchozí je „xml“. - Exports the content of a database to standard output in the specified format. Exportuje obsah databáze na standardní výstup v zadaném formátu. @@ -8197,18 +8675,6 @@ Jádro systému: %3 %4 file empty soubor je prázdný - - malformed string - špatně formovaný řetězec - - - missing closing quote - chybějící uzavírací uvozovka - - - %1: (row, col) %2,%3 - %1: (řádek, sloupec) %2,%3 - AES 256-bit AES 256-bit @@ -8653,13 +9119,89 @@ This option is deprecated, use --set-key-file instead. - Unsupported KDF type, cannot decrypt json file + Unknown passkeys error - Unknown passkeys error + Invalid KDF iterations, cannot decrypt json file + + Unsupported format, ensure your Bitwarden export is password-protected + + + + Only PBKDF and Argon2 are supported, cannot decrypt json file + + + + Reset Shortcuts + + + + Double click an action to change its shortcut + + + + Filter... + + + + Shortcut Conflict + + + + Shortcut %1 conflicts with '%2'. Overwrite shortcut? + + + + Cannot generate valid passphrases because the wordlist is too short + + + + Encrypted files are not supported. + + + + Proton Pass Import + + + + Delete plugin data? + Smazat data zásuvného modulu? + + + Delete plugin data from Entry(s)? + + + + Passkey + + + + Format to use when exporting. Available choices are 'xml', 'csv' or 'html'. Defaults to 'xml'. + + + + start minimized to the system tray + + + + malformed string, possible unescaped delimiter + + + + missing closing delimiter + + + + %1, row: %2, column: %3 + + + + Tags + Štítky + QtIOCompressor @@ -8695,6 +9237,37 @@ This option is deprecated, use --set-key-file instead. Vnitřní chyba v knihovně zlib: + + RemoteHandler + + Command `%1` did not finish in time. Process was killed. + + + + Failed to upload merged database. Command `%1` did not finish in time. Process was killed. + + + + Invalid download parameters provided. + + + + Command `%1` failed to download database. + + + + Invalid database pointer or upload parameters provided. + + + + Command `%1` exited with status code: %2 + + + + Failed to upload merged database. Command `%1` exited with status code: %2 + + + ReportsWidgetBrowserStatistics @@ -8761,6 +9334,10 @@ This option is deprecated, use --set-key-file instead. Exclude from reports Vynechat z přehledů + + Expire Entry(s)… + + Only show entries that have a URL @@ -8775,38 +9352,35 @@ This option is deprecated, use --set-key-file instead. (Expired) - + (Platnost vypršela) + + + Delete plugin data from Entry(s)… + ReportsWidgetHealthcheck - Hover over reason to show additional details. Double-click entries to edit. - Najeďte ukazatelem myši a zobrazí se další podrobnosti. Položky upravíte dvojklikem. + Show expired entries + - Bad - Password quality - Špatné + (Expired) + (Platnost vypršela) + + + Hover over reason to show additional details. Double-click entries to edit. + Najeďte ukazatelem myši a zobrazí se další podrobnosti. Položky upravíte dvojklikem. Bad — password must be changed Špatné — heslo je nutné změnit - - Poor - Password quality - Velmi slabá - Poor — password should be changed Slabé — heslo by se mělo změnit - - Weak - Password quality - Slabá - Weak — consider changing the password Slabé — zvažte změnu hesla @@ -8855,18 +9429,14 @@ This option is deprecated, use --set-key-file instead. Exclude from reports Vynechat z přehledů - - Show expired entries - + + Expire Entry(s)… + Show entries that have been excluded from reports - - (Expired) - - ReportsWidgetHibp @@ -8962,6 +9532,10 @@ This option is deprecated, use --set-key-file instead. Exclude from reports Vynechat z přehledů + + Expire Entry(s)… + + ReportsWidgetPasskeys @@ -9003,7 +9577,7 @@ This option is deprecated, use --set-key-file instead. Relying Party - + Předávající strana Show expired entries @@ -9011,7 +9585,7 @@ This option is deprecated, use --set-key-file instead. (Expired) - + (Platnost vypršela) Export Confirmation @@ -9019,15 +9593,15 @@ This option is deprecated, use --set-key-file instead. The passkey file will be vulnerable to theft and unauthorized use, if left unsecured. Are you sure you want to continue? - + Soubor přístupového klíče bude zranitelný vůči krádeži a neoprávněnému použití, pokud zůstane nezabezpečený. Jste si jistý, že chcete pokračovat? Please wait, list of entries with passkeys is being updated… - + Čekejte prosím, seznam záznamů s přístupovými klíči se aktualizuje... No entries with passkeys. - + Žádné záznamy s přístupovými klíči. @@ -9203,6 +9777,14 @@ This option is deprecated, use --set-key-file instead. No agent running, cannot list identities. Není spuštěný žádný agent, není proto možné vypsat identity + + Failed to remove all SSH identities from agent. + + + + All SSH identities removed from agent. + + SearchHelpWidget @@ -9377,11 +9959,11 @@ This option is deprecated, use --set-key-file instead. <html><head/><body><p>This setting does not override disabling recycle bin prompts </p></body></html> - + <html><head/><body><p>Toto nastavení nezmění deaktivace výzev koše </p></body></html> <html><head/><body><p>This improves compatibility with certain applications which search for password without unlocking the database first.</p><p>But enabling this may also crash the client if the database can not be unlocked within a certain timeout. (Usually 25s, but may be a different value set in applications.) </p></body></html> - + <html><head/><body><p>Toto zlepšuje kompatibilitu s určitými aplikacemi, které hledají heslo bez předchozího odemknutí databáze.</p><p> Povolením může také dojít k chybě klienta, pokud databázi nelze odemknout během určitého časového limitu. (Obvykle 25s, ale hodnota může být jinak nastavená v aplikacích.) </p></body></html> @@ -9488,29 +10070,6 @@ This option is deprecated, use --set-key-file instead. Exportovat do %1 - - ShortcutSettingsWidget - - Double click an action to change its shortcut - - - - Shortcut Conflict - - - - Filter... - - - - Shortcut %1 conflicts with '%2'. Overwrite shortcut? - - - - Reset Shortcuts - - - TagModel @@ -9720,15 +10279,15 @@ Příklad: JBSWY3DPEHPK3PXP Create Database - + Vytvořit databázi Open Database - + Otevřít databázi Import File - + Importovat soubor @@ -9800,11 +10359,15 @@ Příklad: JBSWY3DPEHPK3PXP Nenalezeny žádné hardwarové klíče - <p>If you own a <a href="https://www.yubico.com/">YubiKey</a> or <a href="https://onlykey.io">OnlyKey</a>, you can use it for additional security.</p><p>The key requires one of its slots to be programmed as <a href="https://docs.yubico.com/yesdk/users-manual/application-otp/challenge-response.html">HMAC-SHA1 Challenge-Response</a>.</p> + Refresh hardware keys + Znovu načíst hardwarové klíče + + + <p>If you own a <a href="https://www.yubico.com/">YubiKey</a> or <a href="https://onlykey.io">OnlyKey</a>, you can use it for additional security.</p><p>The key requires one of its slots to be programmed with <a href="https://keepassxc.org/docs/#faq-yubikey-howto">Challenge-Response</a>.</p> - Refresh hardware keys + Hardware keys found, but no slots are configured diff --git a/share/translations/keepassxc_da.ts b/share/translations/keepassxc_da.ts index 86bfaf22b..49728c468 100644 --- a/share/translations/keepassxc_da.ts +++ b/share/translations/keepassxc_da.ts @@ -558,6 +558,10 @@ Lock databases after minimizing the window Lås databaser efter vinduet er blevet minimeret + + Require password repeat when it is visible + Kræv adgangskodegentagelse når den er synlig + Hide passwords when editing them Skjul adgangskoder når de redigeres @@ -592,7 +596,7 @@ Hide TOTP in the entry preview panel - Skjul TOTP forhåndsvisningspanelet + @@ -700,6 +704,10 @@ AutoTypePlatformX11 + + Trying to send invalid keysym. + + Sequence aborted: Caps Lock is on @@ -712,10 +720,6 @@ Unable to get valid keycode for key: - - Trying to send invalid keyboard symbol. - - AutoTypeSelectDialog @@ -848,6 +852,10 @@ Venligst vælg den korrekte database for at gemme loginoplysninger. BrowserPasskeysConfirmationDialog + + KeePassXC: Passkey credentials + + Cancel Annuller @@ -873,41 +881,33 @@ Venligst vælg den korrekte database for at gemme loginoplysninger. - Relying Party: %1 + Do you want to register Passkey for: - Username: %1 + %1 (%2) - KeePassXC - Passkey credentials - KeePassXC - Adgangsnøgle-legitimationsoplysninger - - - Add to existing entry + Existing Passkey found. +Do you want to register a new Passkey for: - Existing passkey found. -Do you want to register a new passkey for: + Select the existing Passkey and press Update to replace it. - Select the existing passkey and press Update to replace it. - - - - Authenticate passkey credentials for: - - - - Do you want to register a passkey for: + Authenticate Passkey credentials for: BrowserService + + KeePassXC: Create a new group + KeePassXC: Opret en ny gruppe + A request for creating a new group "%1" has been received. Do you want to create this group? @@ -916,6 +916,10 @@ Do you want to create this group? Vil du oprette gruppen? + + KeePassXC: New key association request + KeePassXC: Ny anmodning om nøgletilknytning + You have received an association request for the following database: %1 @@ -932,16 +936,28 @@ chrome-laptop. Save and allow access Gem og tillad adgang + + KeePassXC: Overwrite existing key? + KeePassXC: Overskriv eksisterende nøgle? + A shared encryption key with the name "%1" already exists. Do you want to overwrite it? En delt krypteringsnøgle med navnet "%1" eksisterer allerede. Vil du overskrive den? + + KeePassXC: Update Entry + KeePassXC: Opdater post + Do you want to update the information in %1 - %2? Vil du opdatere oplysningerne i %1 - %2? + + KeePassXC: Delete entry + KeePassXC: Slet post + A request for deleting entry "%1" has been received. Do you want to delete the entry? @@ -950,55 +966,6 @@ Do you want to delete the entry? %1 (Passkey) - %1 (Adgangsnøgle) - - - KeePassXC - Create a new group - - - - Disable - Deaktivér - - - KeePassXC - Overwrite existing key? - - - - KeePassXC - Update Entry - - - - KeePassXC - Delete entry - - - - KeePassXC - New key association request - - - - Passkey - Adgangsnøgle - - - KeePassXC - Passkey credentials - KeePassXC - Adgangsnøgle-legitimationsoplysninger - - - Register a new passkey to this entry: - - - - KeePassXC - Update passkey - - - - Entry already has a passkey. -Do you want to overwrite the passkey in %1 - %2? - - - - Register @@ -1247,14 +1214,6 @@ Do you want to overwrite the passkey in %1 - %2? <b>Error:</b> The installed proxy executable is missing from the expected location: %1<br/>Please set a custom proxy location in the advanced settings or reinstall the application. - - Allows using insecure http://localhost with passkeys for testing purposes. - - - - Allow using localhost with passkeys - - CloneDialog @@ -1277,6 +1236,14 @@ Do you want to overwrite the passkey in %1 - %2? CsvImportWidget + + Import CSV fields + Importér CSV-felter + + + filename + filnavn + size, rows, columns størrelse, rækker, kolonner @@ -1385,29 +1352,50 @@ Do you want to overwrite the passkey in %1 - %2? Column %1 + + Imported from CSV file + Importeret fra CSV-fil + + + Original data: + Original data: + + + Error(s) detected in CSV file! + Fejl registreret i CSV-fil! + [%n more message(s) skipped] [%n yderligere meddelelse sprunget over][%n yderligere meddelelser sprunget over] - Failed to parse CSV file: %1 - + Error + Fejl - Imported from CSV file: %1 - + CSV import: writer has errors: +%1 + CSV-import: skriver har fejl: +%1 CsvParserModel + + %1, %2, %3 + file info: bytes, rows, columns + %1, %2, %3 + + + %n byte(s) + %n byte%n bytes + %n row(s) - CSV row count %n række%n rækker %n column(s) - CSV column count %n kolonne%n kolonner @@ -1481,10 +1469,40 @@ Backup database located at %2 Password field Adgangskodefelt + + Enter Additional Credentials (if any): + Angiv yderligere loginoplysninger (hvis de findes): + + + Key File: + Nøglefil: + + + <p>In addition to a password, you can use a secret file to enhance the security of your database. This file can be generated in your database's security settings.</p><p>This is <strong>not</strong> your *.kdbx database file!<br>If you do not have a key file, leave this field empty.</p><p>Click for more information…</p> + <p>Ud over en adgangskode kan du bruge en hemmelig fil til at øge din databases sikkerhed. Denne fil kan genereres i din databases sikkerhedsindstillinger.</p><p>Dette er <strong>ikke</strong> din *.kdbx databasefil!<br>Hvis du ikke har en nøglefil, skal du lade dette felt være tomt.</p><p>Klik for flere oplysninger…</p> + + + Key file help + + Hardware key slot selection Valg af slot til sikkerhedsnøgle + + Hardware Key: + Sikkerhedsnøgle: + + + <p>You can use a hardware security key such as a <strong>YubiKey</strong> or <strong>OnlyKey</strong> with slots configured for HMAC-SHA1.</p> +<p>Click for more information…</p> + <p>Du kan bruge en hardware-sikkerhedsnøgle, f.eks. en <strong>YubiKey</strong> eller <strong>OnlyKey</strong> med slots, der er konfigureret til HMAC-SHA1.</p> +<p>Klik for yderligere oplysninger…</p> + + + Hardware key help + Hjælp til sikkerhedsnøgle + Key file to unlock the database Nøglefil til at låse databasen op @@ -1497,6 +1515,14 @@ Backup database located at %2 Browse… Gennemse… + + Refresh hardware tokens + Genopfrisk hardware-tokens + + + Refresh + Genopfrisk + Unlock Database Lås database op @@ -1585,6 +1611,24 @@ For at forhindre, at denne fejl vises, skal du gå til "Databaseindstilling Cannot use database file as key file Kan ikke åbne databasefil som nøglefil + + You cannot use your database file as a key file. +If you do not have a key file, please leave the field empty. + Du kan ikke bruge din database som nøglefil. +Hvis du ikke har en nøglefil, bedes du lade feltet være tomt. + + + Detecting hardware keys… + Registrerer sikkerhedsnøgler... + + + No hardware keys detected + Ingen sikkerhedsnøgler registreret + + + Select hardware key… + Vælg sikkerhedsnøgle... + authenticate to access the database @@ -1593,54 +1637,6 @@ For at forhindre, at denne fejl vises, skal du gå til "Databaseindstilling Failed to authenticate with Quick Unlock: %1 - - Select Key File: - Vælg nøglefil: - - - <p>In addition to a password, you can use a secret file to enhance the security of your database. This file can be generated in your database's security settings.</p><p>This is <strong>not</strong> your *.kdbx database file!</p> - - - - Click to add a key file. - - - - <a href="#" style="text-decoration: underline">I have a key file</a> - - - - Use hardware key [Serial: %1] - - - - Use hardware key - - - - Your database file is NOT a key file! -If you don't have a key file or don't know what that is, you don't have to select one. - - - - KeePassXC database file selected - - - - The file you selected looks like a database file. -A database file is NOT a key file! - -Are you sure you want to continue with this file?. - - - - No hardware keys found. - - - - Refresh Hardware Keys - - DatabaseSettingWidgetMetaData @@ -1742,10 +1738,18 @@ This may prevent connection to the browser plugin. Vil du virkelig afbryde forbindelsen til alle browsere? Det kan forhindre forbindelse til browserpluginet. + + KeePassXC: No keys found + KeePassXC: Ingen nøgler fundet + No shared encryption keys found in KeePassXC settings. Fandt ingen delte krypteringsnøgler i KeePassXC-indstillinger. + + KeePassXC: Removed keys from database + KeePassXC: Fjernede nøgler fra database + Successfully removed %n encryption key(s) from KeePassXC settings. Det lykkedes at fjerne %n krypteret nøgle fra KeePassXC-indstillingerne.Det lykkedes at fjerne %n krypteret nøgler fra KeePassXC-indstillingerne. @@ -1764,10 +1768,18 @@ Tilladelser til at tilgå poster tilbagekaldes. Abort Afbryd + + KeePassXC: Removed permissions + KeePassXC: Fjernede tilladelser + Successfully removed permissions from %n entry(s). Det lykkedes at fjerne tilladelser fra %n post.Det lykkedes at fjerne tilladelser fra %n poster. + + KeePassXC: No entry with permissions found! + KeePassXC: Ingen nøgler fundet! + The active database does not contain an entry with permissions. Den aktive database indholder ikke en post med tilladelser. @@ -1781,26 +1793,6 @@ Tilladelser til at tilgå poster tilbagekaldes. This is only necessary if your database is a copy of another and the browser extension cannot connect. - - Convert legacy KeePassHTTP attributes to KeePassXC-Browser compatible custom data - - - - No keys found - - - - Removed keys from database - - - - Removed permissions - - - - No entry with permissions found! - - DatabaseSettingsWidgetDatabaseKey @@ -1840,18 +1832,6 @@ Er du sikker på, du vil fortsætte uden en adgangskode? Failed to change database credentials - - Weak password - Svag adgangskode - - - You must enter a stronger password to protect your database. - - - - This is a weak password! For better protection of your secrets, you should choose a stronger password. - - DatabaseSettingsWidgetEncryption @@ -2266,10 +2246,26 @@ Det er helt sikkert en fejl. Rapportér det venligst til udviklerne.CSV file CSV-fil + + Select CSV file + Vælg CSV-fil + Merge database Sammenlæg database + + KeePass 1 database + KeePass 1-database + + + Open KeePass 1 database + Åbn KeePass 1-database + + + Open OPVault + + Export database to CSV file Eksportér database til CSV-fil @@ -2302,6 +2298,15 @@ Det er helt sikkert en fejl. Rapportér det venligst til udviklerne.You are about to export your database to an unencrypted file. This will leave your passwords and sensitive information vulnerable! Are you sure you want to continue? Du er ved at eksportere din database til en ukrypteret fil. Dette vil gøre dine adgangskoder og følsomme oplysninger sårbare! Er du sikker på, at du vil fortsætte? + + New Database + Ny database + + + %1 [New Database] + Database tab name modifier + %1 [Ny database] + %1 [Locked] Database tab name modifier @@ -2492,15 +2497,6 @@ Så sikre gem fra og prøv igen? Could not find database file: %1 Kunne ikke finde databasefil: %1 - - New Database - Ny database - - - %1 [New Database] - Database tab name modifier - %1 [Ny database] - EditEntryWidget @@ -2812,6 +2808,10 @@ Would you like to correct it? EditEntryWidgetBrowser + + These settings affect to the entry's behaviour with the browser extension. + + General Generelt @@ -2840,6 +2840,10 @@ Would you like to correct it? Do not use this entry with HTTP Basic Auth + + Additional URL's + + Add Tilføj @@ -2852,14 +2856,6 @@ Would you like to correct it? Edit Rediger - - These settings affect the entry's behaviour with the browser extension. - - - - Additional URLs - - EditEntryWidgetHistory @@ -3172,14 +3168,6 @@ Would you like to correct it? Omit WWW subdomain from matching toggle for this and sub groups - - Restrict matching to given browser key: - - - - Restrict matching to given browser key toggle for this and sub groups - - EditGroupWidgetKeeShare @@ -3411,6 +3399,10 @@ Supported extensions are: %1. Unable to fetch favicon. Kan ikke hente favicon. + + You can enable the DuckDuckGo website icon service under Tools -> Settings -> Security + + Existing icon selected. @@ -3443,10 +3435,6 @@ Supported extensions are: %1. The following icon(s) failed: Følgende ikon mislykkedes:Følgende ikoner mislykkedes: - - You can enable the DuckDuckGo website icon service under Application Settings -> Security - - EditWidgetProperties @@ -3651,6 +3639,11 @@ Det kan få de påvirkede plugins til at svigte. Confirm Overwrite Attachment + + Attachment "%1" already exists. +Would you like to overwrite the existing attachment? + + Confirm Attachment @@ -3681,11 +3674,6 @@ Do you want to save the changes to your database? Error: %1 - - Attachment "%1" already exists. -Would you like to overwrite the existing attachment? - - EntryAttributesModel @@ -4239,147 +4227,6 @@ You can enable the DuckDuckGo website icon service in the security section of th Downloader faviconer (%1/%2)… - - ImportWizard - - Import Wizard - - - - - ImportWizardPageReview - - WizardPage - Assistentside - - - Entry count: %1 - - - - Group - Gruppe - - - Title - Titel - - - Username - Brugernavn - - - Password - Adgangskode - - - Url - - - - - ImportWizardPageSelect - - Form - Formular - - - Import File Selection - - - - Password: - Adgangskode: - - - Key File: - Nøglefil: - - - Browse… - Gennemse… - - - Import Into: - - - - New Database - Ny database - - - No unlocked databases available - - - - Existing Database: - - - - Import File: - - - - Comma Separated Values (.csv) - - - - 1Password Export (.1pux) - - - - 1Password Vault (.opvault) - - - - Bitwarden (.json) - - - - KeePass 1 Database (.kdb) - - - - Open OPVault - - - - Select import file - - - - All files - Alle filer - - - Key files - Nøglefiler - - - Select key file - Vælg nøglefil - - - Comma Separated Values - - - - 1Password Export - - - - Bitwarden JSON Export - - - - 1Password Vault - - - - KeePass1 Database - - - KMessageWidget @@ -4814,6 +4661,17 @@ Linje %2, kolonne %3 Kunne ikke åbne privat nøgle + + KeePass1OpenWidget + + Import KeePass1 Database + Importér KeePass1-database + + + Unable to open the database. + Kan ikke åbne databasen. + + KeePass1Reader @@ -5169,6 +5027,10 @@ Are you sure you want to continue with this file? &Recent Databases &Seneste databaser + + &Import + &Importér + &Export &Eksportér @@ -5237,18 +5099,34 @@ Are you sure you want to continue with this file? &New Database… &Ny database... + + Create a new database + Opret en ny database + &Merge From Database… &Flet fra database... + + Merge from another KDBX database + Sammenlæg fra en anden KDBX-database + &New Entry… &Ny post... + + Add a new entry + Tilføj en ny post + &Edit Entry… &Rediger post + + View or edit entry + Vis eller rediger post + &Delete Entry… &Slet post @@ -5257,6 +5135,10 @@ Are you sure you want to continue with this file? &New Group… &Ny gruppe... + + Add a new group + Tilføj en ny gruppe + &Edit Group… &Rediger gruppe... @@ -5289,10 +5171,18 @@ Are you sure you want to continue with this file? Database &Reports… Database&reporter… + + Statistics, health check, etc. + + &Database Settings… &Databaseindstillinger… + + Database settings + Databaseindstillinger + &Clone Entry… &Klon post @@ -5301,18 +5191,34 @@ Are you sure you want to continue with this file? Move u&p + + Move entry one step up + Ryk post et trin op + Move do&wn + + Move entry one step down + Ryk post et tin ned + Copy &Username Kopiér &brugernavn + + Copy username to clipboard + Kopiér brugernavn til udklipsholder + Copy &Password Kopiér &Adgangskode + + Copy password to clipboard + Kopiér adgangskode til udklipsholder + &Settings &Indstillinger @@ -5345,14 +5251,26 @@ Are you sure you want to continue with this file? &Title &Titel + + Copy title to clipboard + Kopiér titel til udklipsholder + Copy &URL + + Copy URL to clipboard + Kopiér URL til udklipsholder + &Notes &Bemærkninger + + Copy notes to clipboard + Kopiér bemærkninger til udklipsholder + &CSV File… &CSV-fil… @@ -5365,14 +5283,26 @@ Are you sure you want to continue with this file? KeePass 1 Database… + + Import a KeePass 1 database + Importér en KeePass 1-database + 1Password Vault… + + Import a 1Password Vault + Importér en 1Password-boks + CSV File… CSV-fil… + + Import a CSV file + Importér en CSV-fil + Show TOTP Vis TOTP @@ -5417,6 +5347,10 @@ Are you sure you want to continue with this file? &Online Help Online hjælp + + Go to online documentation + + &User Guide &Brugerguide @@ -5461,10 +5395,6 @@ Are you sure you want to continue with this file? Classic (Platform-native) Klassisk - - Show Menubar - - Show Toolbar Vis værktøjsbjælke @@ -5493,6 +5423,10 @@ Are you sure you want to continue with this file? &XML File… &XML-fil… + + XML File… + XML-fil… + Clear history Ryd historik @@ -5573,272 +5507,16 @@ We recommend you use the AppImage available on our downloads page. Allow Screen Capture - - 1Password 1PUX... - - - - Import a 1Password 1PUX file - - - - Import… - - Passkeys… - Adgangsnøgler… + + + + Passkeys + Import Passkey - Importér adgangsnøgle - - - Quit Application - - - - Open About Dialog - - - - Open Database - - - - Create Database - - - - Merge From Database - - - - Create Entry - - - - Edit Entry - Rediger post - - - Delete Entry - - - - Create Group - - - - Edit Group - Rediger gruppe - - - Delete Group - - - - Download All Favicons - - - - Sort Groups A-Z - - - - Sort Groups Z-A - - - - Save Database As - - - - Show Database Security - - - - Show Database Reports - - - - Show Database Settings - - - - Show Passkeys - - - - Clone Entry - - - - Move Entry Up - - - - Move Entry Down - - - - Copy Username - Kopiér brugernavn - - - Copy Password - Kopiér adgangskode - - - Show Application Settings - - - - Show Password Generator - - - - Perform Auto-Type: {USERNAME} - - - - Perform Auto-Type: {USERNAME}{ENTER} - - - - Perform Auto-Type: {PASSWORD} - - - - Perform Auto-Type: {PASSWORD}{ENTER} - - - - Perform Auto-Type: {TOTP} - - - - Copy Title - - - - Copy URL - - - - Copy Notes - - - - Export to CSV - - - - Export to HTML - - - - Import KeePass1 Database - Importér KeePass1-database - - - Import 1Password Vault - - - - Import CSV File - - - - Show TOTP QR Code - - - - Set up TOTP - - - - Empty Recycle Bin - - - - Open Donation Website - - - - Open Bug Report - - - - Open Online Documentation - - - - Open Keyboard Shortcuts Guide - - - - Save Database Backup - - - - SSH Agent: Add Key - - - - SSH Agent: Remove Key - - - - Toggle Compact Mode - - - - Set Theme: Automatic - - - - Set Theme: Light - - - - Set Theme: Dark - - - - Set Theme: Classic - - - - Toggle Show Menubar - - - - Toggle Show Toolbar - - - - Toggle Show Preview Panel - - - - Toggle Always on Top - - - - Toggle Hide Usernames - - - - Toggle Hide Passwords - - - - Export to XML - - - - Toggle Allow Screen Capture @@ -5898,6 +5576,26 @@ We recommend you use the AppImage available on our downloads page. Overwriting %1 [%2] Overskriver %1 [%2] + + older entry merged from database "%1" + gammel post sammenlagt fra databasen "%1" + + + Adding backup for older target %1 [%2] + Tilføjer sikkerhedskopi til ældre mål %1 [%2] + + + Adding backup for older source %1 [%2] + Tilføjer sikkerhedskopi til ældre kilde %1 [%2] + + + Reapplying older target entry on top of newer source %1 [%2] + Genanvender ældre målpost oven på nyere kilde %1 [%2] + + + Reapplying older source entry on top of newer target %1 [%2] + Genanvender ældre kildepost oven på nyere mål %1 [%2] + Synchronizing from newer source %1 [%2] Synkroniserer fra nyere kilde %1 [%2] @@ -6037,6 +5735,14 @@ We recommend you use the AppImage available on our downloads page. + + OpVaultOpenWidget + + Read Database did not produce an instance +%1 + + + OpVaultReader @@ -6202,11 +5908,15 @@ We recommend you use the AppImage available on our downloads page. PasskeyExportDialog KeePassXC - Passkey Export - KeePassXC - Adgangsnøgle-eksport + + + + Export the following Passkey entries. + Filenames will be generated with title and .passkey file extension. - Filnavne vil blive genereret med titel og filendelsen .passkey. + Export entries @@ -6224,24 +5934,18 @@ We recommend you use the AppImage available on our downloads page. Export to folder - - Export the following passkey entries. - - PasskeyExporter KeePassXC: Passkey Export - KeePassXC: Adgangsnøgle-eksport + File "%1.passkey" already exists. Do you want to overwrite it? - Filen "%1.passkey" findes allerede. -Ønsker du at overskrive den? - + Cannot open file @@ -6260,12 +5964,24 @@ Do you want to overwrite it? PasskeyImportDialog KeePassXC - Passkey Import - KeePassXC - Adgangsnøgle-import + + + + Do you want to import the Passkey? + + + + URL: %1 + Username: %1 + + Use default group (Imported Passkeys) + + Group Gruppe @@ -6274,9 +5990,13 @@ Do you want to overwrite it? Database Database + + Select Database + + Import Passkey - Importér adgangsnøgle + Import @@ -6287,27 +6007,11 @@ Do you want to overwrite it? Annuller - Entry - Post - - - Create new entry + Database: %1 - Relying Party: %1 - - - - Import the following passkey: - - - - Import the following passkey to this entry: - - - - Default passkeys group (Imported Passkeys) + Group: @@ -6315,12 +6019,16 @@ Do you want to overwrite it? PasskeyImporter Passkey file - Adgangsnøglefil + All files Alle filer + + Open Passkey file + + Cannot open file @@ -6330,25 +6038,15 @@ Do you want to overwrite it? - Open passkey file + Cannot import Passkey - Cannot import passkey + Cannot import Passkey file "%1". Data is missing. - Cannot import passkey file "%1". Data is missing. - - - - Cannot import passkey file "%1". -The following data is missing: -%2 - - - - Cannot import passkey file "%1". Private key is missing or malformed. + Cannot import Passkey file "%1". Private key is missing or malformed. @@ -6731,7 +6429,7 @@ Do you want to overwrite it? Fremragende - Toggle password visibility using Control + H. Open the password generator using Control + G. + Toggle password visibilty using Control + H. Open the password generator using Control + G. @@ -6788,10 +6486,6 @@ Do you want to overwrite it? Continue - - Continue with weak password - - QObject @@ -7197,6 +6891,12 @@ Do you want to overwrite it? time + + Set the key file for the database. +This options is deprecated, use --set-key-file instead. + Indstil nøglefilen for databasen. +Denne indstilling er forældet, brug i stedet --set-key-file. + Set the key file for the database. @@ -8354,6 +8054,10 @@ Kerne: %3 %4 read password of the database from stdin læs adgangskode til databasen fra stdin + + Locked databases. + Låste databaser. + Database failed to lock. Låsning af database mislykkedes. @@ -8416,43 +8120,6 @@ Kerne: %3 %4 allow screenshots and app recording (Windows/macOS) - - Set the key file for the database. -This option is deprecated, use --set-key-file instead. - - - - Databases have been locked. - - - - Attestation not supported - - - - Credential is excluded - - - - Passkeys request canceled - Anmodning om pasnøgler annulleret - - - Invalid user verification - - - - Empty public key - - - - Invalid URL provided - - - - Passkeys - Adgangsnøgler - AES initialization failed @@ -8465,10 +8132,6 @@ This option is deprecated, use --set-key-file instead. Failed to store in Linux Keyring - - Polkit returned an error: %1 - - Could not locate key in keyring @@ -8493,6 +8156,10 @@ This option is deprecated, use --set-key-file instead. No Quick Unlock provider is available + + Polkit returned an error: %1 + + Failed to init KeePassXC crypto. @@ -8510,121 +8177,7 @@ This option is deprecated, use --set-key-file instead. - Origin is empty or not allowed - - - - Effective domain is not a valid domain - - - - Origin and RP ID do not match - - - - No supported algorithms were provided - - - - Wait for timer to expire - - - - Challenge is shorter than required minimum length - - - - user.id does not match the required length - - - - Favorite - Tag for favorite entries - - - - File does not exist. - - - - Cannot open file: %1 - - - - Cannot parse file: %1 at position %2 - - - - Failed to decrypt json file: %1 - - - - Invalid encKeyValidation field - - - - Invalid cipher list within encKeyValidation field - - - - Wrong password - - - - Invalid encrypted data field - - - - Invalid cipher list within encrypted data field - - - - Cannot initialize cipher - - - - Cannot decrypt data - - - - Bitwarden Import - - - - Archived - Tag for archived entries - - - - Invalid 1PUX file format: Not a valid ZIP file. - - - - Invalid 1PUX file format: Missing export.data - - - - 1Password Import - - - - Enter Shortcut - - - - Action - - - - Shortcuts - - - - Unsupported KDF type, cannot decrypt json file - - - - Unknown passkeys error + Passkeys @@ -8944,6 +8497,14 @@ This option is deprecated, use --set-key-file instead. List of entry URLs + + Please wait, list of entries with Passkeys is being updated… + + + + No entries with Passkeys. + + Title Titel @@ -8980,22 +8541,6 @@ This option is deprecated, use --set-key-file instead. (Expired) - - Export Confirmation - - - - The passkey file will be vulnerable to theft and unauthorized use, if left unsecured. Are you sure you want to continue? - - - - Please wait, list of entries with passkeys is being updated… - - - - No entries with passkeys. - - ReportsWidgetStatistics @@ -9314,10 +8859,30 @@ This option is deprecated, use --set-key-file instead. Confirm when passwords are retrieved by clients + + <html><head/><body><p><span style=" + font-family:'-apple-system','BlinkMacSystemFont','Segoe UI','Helvetica','Arial','sans-serif','Apple Color + Emoji','Segoe UI Emoji'; font-size:14px; color:#24292e; background-color:#ffffff;">This setting does + not override disabling recycle bin prompts</span></p></body></html> + + <html><head/><body><p><span style=" + font-family:'-apple-system','BlinkMacSystemFont','Segoe UI','Helvetica','Arial','sans-serif','Apple Color + Emoji','Segoe UI Emoji'; font-size:14px; color:#24292e; background-color:#ffffff;">Denne indstilling + tilsidesætter ikke deaktivering af papirkurvs-prompter</span></p></body></html> + + Confirm when clients request entry deletion + + <html><head/><body><p>This improves compatibility with certain applications + which search for password without unlocking the database first.</p><p>But enabling this may also + crash the client if the database can not be unlocked within a certain timeout. (Usually 25s, but may be a + different value set in applications.)</p></body></html> + + + Prompt to unlock database before searching Bed om at låse databasen op før søgning @@ -9342,14 +8907,6 @@ This option is deprecated, use --set-key-file instead. Save current changes to activate the plugin and enable editing of this section. - - <html><head/><body><p>This setting does not override disabling recycle bin prompts </p></body></html> - - - - <html><head/><body><p>This improves compatibility with certain applications which search for password without unlocking the database first.</p><p>But enabling this may also crash the client if the database can not be unlocked within a certain timeout. (Usually 25s, but may be a different value set in applications.) </p></body></html> - - SettingsWidgetKeeShare @@ -9455,29 +9012,6 @@ This option is deprecated, use --set-key-file instead. Eksportér til %1 - - ShortcutSettingsWidget - - Double click an action to change its shortcut - - - - Shortcut Conflict - - - - Filter... - - - - Shortcut %1 conflicts with '%2'. Overwrite shortcut? - - - - Reset Shortcuts - - - TagModel @@ -9672,6 +9206,26 @@ Example: JBSWY3DPEHPK3PXP Start storing your passwords securely in a KeePassXC database Gem dine adgangskoder sikkert i en KeePassXC-database + + Create new database + Opret en ny database + + + Open existing database + Åbn en eksisterende database + + + Import from KeePass 1 + Importér fra KeePass 1 + + + Import from 1Password + Importér fra 1Password + + + Import from CSV + Importér fra CSV + Recent databases Seneste databaser @@ -9684,18 +9238,6 @@ Example: JBSWY3DPEHPK3PXP Welcome to KeePassXC %1 Velkommen til KeePassXC %1 - - Create Database - - - - Open Database - - - - Import File - - WinUtils @@ -9714,6 +9256,10 @@ Example: JBSWY3DPEHPK3PXP YubiKey + + %1 No interface, slot %2 + + General: @@ -9725,6 +9271,14 @@ Example: JBSWY3DPEHPK3PXP YubiKeyEditWidget + + Refresh hardware tokens + Genopfrisk hardware-tokens + + + Refresh + Genopfrisk + Hardware key slot selection Valg af slot til sikkerhedsnøgle @@ -9757,6 +9311,10 @@ Example: JBSWY3DPEHPK3PXP Challenge-Response set, click to change or remove + + <p>If you own a <a href="https://www.yubico.com/">YubiKey</a> or <a href="https://onlykey.io">OnlyKey</a>, you can use it for additional security.</p><p>The key requires one of its slots to be programmed as <a href="https://www.yubico.com/products/services-software/challenge-response/">HMAC-SHA1 Challenge-Response</a>.</p> + <p>Hvis du ejer en <a href="https://www.yubico.com/">YubiKey</a> eller <a href="https://onlykey.io">OnlyKey</a>, kan du bruge den som ekstra sikkerhed.</p><p>Nøglen kræver, at et af dens slots er programmeret som <a href="https://www.yubico.com/products/services-software/challenge-response/">HMAC-SHA1 udfordrings-svar</a>.</p> + Detecting hardware keys… Registrerer sikkerhedsnøgler… @@ -9765,21 +9323,28 @@ Example: JBSWY3DPEHPK3PXP No hardware keys detected Ingen sikkerhedsnøgler registreret + + + YubiKeyInterface - <p>If you own a <a href="https://www.yubico.com/">YubiKey</a> or <a href="https://onlykey.io">OnlyKey</a>, you can use it for additional security.</p><p>The key requires one of its slots to be programmed as <a href="https://docs.yubico.com/yesdk/users-manual/application-otp/challenge-response.html">HMAC-SHA1 Challenge-Response</a>.</p> - - - - Refresh hardware keys + %1 Invalid slot specified - %2 YubiKeyInterfacePCSC + + (PCSC) %1 [%2] Challenge-Response - Slot %3 + + The YubiKey PCSC interface has not been initialized. + + Hardware key is currently in use. + Sikkerhedsnøgle er i øjeblikket i brug + Could not find or access hardware key with serial number %1. Please present it to continue. Kunne ikke finde eller få adgang til sikkerhedsnøglen med serienummer %1. Præsenter den for at fortsætte. @@ -9796,21 +9361,6 @@ Example: JBSWY3DPEHPK3PXP Failed to complete a challenge-response, the PCSC error code was: %1 - - (NFC) %1 [%2] - Slot %3, %4 - YubiKey display fields - - - - Press - USB Challenge-Response Key interaction request - Tryk - - - Passive - USB Challenge-Response Key no interaction required - Passiv - YubiKeyInterfaceUSB @@ -9818,6 +9368,14 @@ Example: JBSWY3DPEHPK3PXP Unknown Ukendt + + (USB) %1 [%2] Configured Slot - %3 + + + + (USB) %1 [%2] Challenge-Response - Slot %3 - %4 + + Press USB Challenge-Response Key interaction request @@ -9832,6 +9390,10 @@ Example: JBSWY3DPEHPK3PXP The YubiKey USB interface has not been initialized. + + Hardware key is currently in use. + Sikkerhedsnøgle er i øjeblikket i brug. + Could not find hardware key with serial number %1. Please plug it in to continue. Kunne ikke finde sikkerhedsnøglen med serienummer %1. Sæt den i for at fortsætte. @@ -9848,15 +9410,5 @@ Example: JBSWY3DPEHPK3PXP Failed to complete a challenge-response, the specific error was: %1 - - %1 [%2] - Slot %3 - YubiKey NEO display fields - - - - %1 [%2] - Slot %3, %4 - YubiKey display fields - - \ No newline at end of file diff --git a/share/translations/keepassxc_de.ts b/share/translations/keepassxc_de.ts index 5182a9b66..6e31310e3 100644 --- a/share/translations/keepassxc_de.ts +++ b/share/translations/keepassxc_de.ts @@ -58,8 +58,7 @@ <html><head/><body><p><span style=" font-weight:600;">%1 </span>is requesting access to the following entries:</p></body></html> - <html><head/><body><p><span style=" font-weight:600;">%1 </span>fordert Zugriff auf die folgenden Einträge an: -</p></body></html> + <html><head/><body><p><span style=" font-weight:600;">%1 </span>fordert Zugriff auf die folgenden Einträge: </p></body></html> @@ -100,7 +99,7 @@ Allow All && &Future - Alle erlauben && Zukünftige + Alle erlauben && &Zukünftige @@ -219,18 +218,50 @@ You must restart the application to set the new language. Would you like to restart now? Zum Ändern der Sprache müssen Sie die Anwendung neu starten. Möchten Sie jetzt neu starten? - - Reset Settings? - Einstellungen zurücksetzen? - - - Are you sure you want to reset all general and security settings to default? - Wollen Sie alle allgemeinen und Sicherheitseinstellungen auf die Voreinstellung zurücksetzen? - Select backup storage directory Verzeichnis für die Datensicherung auswählen + + Confirm Reset + Zurücksetzen bestätigen + + + Are you sure you want to reset all settings to default? + Sind Sie sicher, dass Sie alle Einstellungen auf die Standardwerte zurücksetzen wollen? + + + Import KeePassXC Settings + KeePassXC-Einstellungen importieren + + + Failed to import settings from %1, not a valid settings file. + Fehler beim Importieren von Einstellungen aus %1, keine gültige Einstellungsdatei. + + + Export KeePassXC Settings + KeePassXC-Einstellungen exportieren + + + Small + Klein + + + Normal + Normal + + + Medium + Medium + + + Large + Groß + + + Custom + Benutzerdefiniert + ApplicationSettingsWidgetGeneral @@ -260,7 +291,7 @@ Remember previously used databases - Zuletzt verwendete Datenbanken merken + Zuletzt verwendete Datenbanken merken: recent files @@ -282,25 +313,6 @@ Include beta releases when checking for updates Betaversionen bei Update-Prüfung einbeziehen - - On database unlock, show entries that - Beim Entsperren der Datenbank Einträge anzeigen, die - - - have expired - On database unlock, show entries that... - abgelaufen sind - - - days - On database unlock, show entries that will expire within %1 days - Tagen - - - will expire within - On database unlock, show entries that... - ablaufen innerhalb von - File Management Dateiverwaltung @@ -325,25 +337,13 @@ Backup database file before saving Vor dem Speichern Backup der Datenbank erstellen - - Backup destination - Sicherungsziel - - - Specifies the database backup file location. Occurrences of "{DB_FILENAME}" are replaced with the filename of the saved database without extension. {TIME:<format>} is replaced with the backup time, see https://doc.qt.io/qt-5/qdatetime.html#toString. <format> defaults to format string "dd_MM_yyyy_hh-mm-ss". - Gibt den Speicherort der Datenbank-Sicherungsdatei an. Das Vorkommen von „{DB_FILENAME}“ wird durch den Dateinamen der gesicherten Datenbank ohne Erweiterung ersetzt. {TIME:<format>} wird durch die Sicherungszeit ersetzt, siehe https://doc.qt.io/qt-5/qdatetime.html#toString. <format>Standardmäßig wird die Formatzeichenfolge „dd_MM_yyyy_hh-mm-ss“ verwendet. - {DB_FILENAME}.old.kdbx {DB_FILENAME}.alt.kdbx - - Choose... - Auswählen… - Use alternative saving method (may solve problems with Dropbox, Google Drive, GVFS, etc.) - Alternative Speichermethode verwenden (kann Probleme von Dropbox, Google Drive, GVFS usw. lösen) + Alternative Speichermethode verwenden (kann Probleme mit Dropbox, Google Drive, GVFS usw. lösen) Temporary file moved into place @@ -507,6 +507,71 @@ Remember last typed entry for: Zuletzt eingegebenen Eintrag merken für: + + On database unlock, show entries that will expire within + Beim Entsperren der Datenbank Einträge anzeigen, die ablaufen in: + + + On database unlock, show entries that will expire within + Beim Entsperren der Datenbank Einträge anzeigen, die ablaufen in: + + + days + number of days warning for password expiration + Tagen + + + Destination format: + Zielformat: + + + <html><head/><body><p><span style=" font-weight:600;">{DB_FILENAME}</span> is replaced with the filename of the saved database without extension</p><p><span style=" font-weight:600;">{TIME:&lt;format&gt;}</span> is replaced with the specified time format (default: dd_MM_yyyy_hh-mm-ss)</p><p>See the User Guide for more details</p></body></html> + <html><head/><body><p><span style=" font-weight:600;">{DB_FILENAME}</span> wird durch den Dateinamen der gespeicherten Datenbank ohne Erweiterung ersetzt</p><p><span style=" font-weight:600;">{TIME:&lt;format&gt;}</span> wird durch das angegebene Zeitformat ersetzt (Standard: dd_MM_yyyy_hh-mm-ss)</p><p>Weitere Einzelheiten finden Sie im Benutzerhandbuch</p></body></html> + + + Choose folder... + Ordner auswählen… + + + Show confirmation before moving entries to recycle bin + Bestätigung vor dem Verschieben von Einträgen in den Papierkorb anzeigen + + + Copy data on double clicking field in entry view + Daten beim Doppelklick auf ein Feld in der Eintragsansicht kopieren + + + Show toolbar + Symbolleiste anzeigen + + + Show the menu bar by pressing the Alt key + Menüleiste durch Drücken der Alt-Taste anzeigen + + + Show menubar + Menüleiste anzeigen + + + Import settings… + Einstellungen importieren… + + + Export settings… + Einstellungen exportieren… + + + Open browser on double clicking URL field in entry view + Browser bei Doppelklick auf das URL-Feld in der Eintragsansicht öffnen + + + Font size: + Schriftgröße: + + + Font size selection + Auswahl der Schriftgröße + ApplicationSettingsWidgetSecurity @@ -572,18 +637,6 @@ Hide passwords in the entry preview panel Passwörter im Eintrags-Vorschau-Panel verstecken - - Hide entry notes by default - Eintrags-Notizen standardmäßig verstecken - - - Move entries to recycle bin without confirmation - Einträge ohne Bestätigung in den Papierkorb verschieben - - - Enable double click to copy the username/password entry columns - Benutzernamen/Passwort per Doppelklick kopieren - Privacy Datenschutz @@ -596,6 +649,18 @@ Hide TOTP in the entry preview panel TOTP in der Eintragsvorschau verstecken + + Lock databases when switching user + Datenbanken beim Benutzerwechsel sperren + + + Lock Options + Optionen sperren + + + Hide notes in the entry preview panel + Notizen in der Eintragsvorschau verstecken + AutoType @@ -643,20 +708,6 @@ Entry does not have attribute for PICKCHARS: %1 Eintrag hat kein Attribut für PICKCHARS: %1 - - Invalid conversion type: %1 - Ungültiger Konvertierungstyp: %1 - - - Invalid conversion syntax: %1 - Ungültige Konvertierungssyntax: %1 - - - Invalid regular expression syntax %1 -%2 - Ungültige Syntax des regulären Ausdrucks %1 -%2 - Invalid placeholder: %1 Ungültiger Platzhalter: %1 @@ -888,24 +939,25 @@ Bitte wählen Sie die richtige Datenbank zum Speichern der Anmeldedaten. Add to existing entry - + Einem bestehenden Eintrag hinzufügen Existing passkey found. Do you want to register a new passkey for: - + Vorhandenen Passkey gefunden. +Möchten Sie einen neuen Passkey registrieren für: Select the existing passkey and press Update to replace it. - + Wählen Sie den vorhandenen Passkey aus und drücken Sie Update, um ihn zu ersetzen. Authenticate passkey credentials for: - + Passkey-Anmeldedaten authentifizieren für: Do you want to register a passkey for: - + Möchten Sie ein Passkey registrieren für: @@ -989,16 +1041,17 @@ Möchten Sie den Eintrag löschen? Register a new passkey to this entry: - + Registrieren Sie einen neuen Passkey für diesen Eintrag: KeePassXC - Update passkey - + KeePassXC - Passkey aktualisieren Entry already has a passkey. Do you want to overwrite the passkey in %1 - %2? - + Eintrag hat bereits einen Passkey. +Möchten Sie den Passkey in %1 - %2 überschreiben? Register @@ -1023,10 +1076,6 @@ Do you want to overwrite the passkey in %1 - %2? General Allgemein - - Browsers installed as snaps are currently not supported. - Browser, die als Snaps installiert sind, werden derzeit nicht unterstützt. - Enable integration for these browsers: Integration für diese Browser aktivieren: @@ -1108,12 +1157,12 @@ Do you want to overwrite the passkey in %1 - %2? Never ask before accessing credentials Credentials mean login data requested via browser extension - Niemals fragen, bevor auf Anmeldedaten zugegriffen wird + Niemals vor dem Zugriff auf Anmeldeinformationen fragen Never ask before updating credentials Credentials mean login data requested via browser extension - Niemals fragen, bevor Anmeldedaten aktualisiert werden + Niemals vor der Aktualisierung der Anmeldedaten fragen Do not ask permission for HTTP Basic Auth @@ -1159,7 +1208,7 @@ Do you want to overwrite the passkey in %1 - %2? Browser for custom proxy file - Browser für benutzerdefinierte Proxydatei + Browser für benutzerdefinierte Proxy-Datei Browse… @@ -1198,18 +1247,6 @@ Do you want to overwrite the passkey in %1 - %2? Custom extension ID Benutzerdefinierte Erweiterungs-ID - - Due to Snap sandboxing, you must run a script to enable browser integration.<br />You can obtain this script from %1 - Aufgrund von Snap Sandboxing müssen Sie ein Skript ausführen, um die Browser-Integration zu aktivieren.<br />Sie können dieses Skript erhalten unter %1 - - - KeePassXC-Browser is needed for the browser integration to work. <br />Download it for %1 and %2 and %3. %4 - KeePassXC-Browser wird für die Browserintegration benötigt. <br />Laden Sie es für %1 und %2 und %3 herunter. %4 - - - Please see special instructions for browser extension use below - Bitte beachten Sie die untenstehenden speziellen Anweisungen für die Verwendung der Browser-Erweiterung - Executable Files Ausführbare Dateien @@ -1252,11 +1289,19 @@ Do you want to overwrite the passkey in %1 - %2? Allows using insecure http://localhost with passkeys for testing purposes. - + Nutzung von unsicheren http://localhost mit Passkeys zu Testzwecken zulassen. Allow using localhost with passkeys - + Nutzung von localhost mit Passkeys zulassen + + + KeePassXC-Browser is needed for the browser integration to work. <br />Download it for %1 and %2 and %3. + KeePassXC-Browser wird für die Browserintegration benötigt. <br />Laden Sie ihn für %1 und %2 und %3 herunter. + + + Browsers installed using Snap or Flatpak are not supported with exception to Firefox installed using Snap. + Mit Snap oder Flatpak installierte Browser werden nicht unterstützt, mit Ausnahme von Firefox, der mit Snap installiert wurde. @@ -1400,6 +1445,20 @@ Do you want to overwrite the passkey in %1 - %2? Imported from CSV file: %1 Aus CSV-Datei: %1 importiert + + No Title Selected + Kein Titel ausgewählt + + + No title column was selected, entries will be hard to tell apart. +Are you sure you want to import? + Es wurde keine Titelspalte ausgewählt, sodass die Einträge schwer zu unterscheiden sind. +Sind Sie sicher, dass Sie importieren möchten? + + + Tags + Tags + CsvParserModel @@ -1463,6 +1522,14 @@ Sicherungskopie der Datenbank ist in %2 Recycle Bin Papierkorb + + Database file read error. + Fehler beim Lesen der Datenbankdatei. + + + No file path was provided. + Es wurde kein Dateipfad angegeben. + DatabaseOpenDialog @@ -1611,14 +1678,6 @@ Um diesen Fehler zu vermeiden, müssen Sie zu „Datenbankeinstellungen → Sich <p>In addition to a password, you can use a secret file to enhance the security of your database. This file can be generated in your database's security settings.</p><p>This is <strong>not</strong> your *.kdbx database file!</p> <p>Zusätzlich zu einem Passwort können Sie eine geheime Datei verwenden, um die Sicherheit Ihrer Datenbank zu erhöhen. Diese Datei kann in den Sicherheitseinstellungen Ihrer Datenbank erzeugt werden.</p><p>Dies ist <strong>nicht</strong> Ihre *.kdbx-Datenbankdatei!</p> - - Click to add a key file. - Durch Anklicken können Sie eine Schlüsseldatei hinzufügen. - - - <a href="#" style="text-decoration: underline">I have a key file</a> - <a href="#" style="text-decoration: underline">Ich habe eine Schlüsseldatei</a> - Use hardware key [Serial: %1] Hardwareschlüssel verwenden [Seriennummer: %1] @@ -1655,6 +1714,18 @@ Sind Sie sicher, dass Sie mit dieser Datei fortfahren wollen? Refresh Hardware Keys Hardwareschlüssel aktualisieren + + Click to add a key file. + Durch Anklicken können Sie eine Schlüsseldatei hinzufügen. + + + <a href="#" style="text-decoration: underline">I have a key file</a> + <a href="#" style="text-decoration: underline">Ich habe eine Schlüsseldatei</a> + + + Hardware keys found, but no slots are configured. + Hardwareschlüssel gefunden, es sind aber keine Slots konfiguriert. + DatabaseSettingWidgetMetaData @@ -1689,6 +1760,22 @@ Sind Sie sicher, dass Sie mit dieser Datei fortfahren wollen? Maintenance Wartung + + KeeShare + KeeShare + + + Secret Service Integration + Secret-Service-Integration + + + Remote Sync + Fernsynchronisierung + + + Database Settings: %1 + Datenbankeinstellungen: %1 + DatabaseSettingsWidgetBrowser @@ -1859,14 +1946,14 @@ Wollen Sie wirklich ohne Passwort fortfahren? Weak password Schwaches Passwort - - You must enter a stronger password to protect your database. - Sie müssen ein stärkeres Passwort eingeben, um Ihre Datenbank zu schützen. - This is a weak password! For better protection of your secrets, you should choose a stronger password. Dies ist ein schwaches Passwort! Um Ihre Geheimnisse besser zu schützen, sollten Sie ein stärkeres Passwort wählen. + + The provided password does not meet the minimum quality requirement. + Das übermittelte Passwort entspricht nicht den Mindestanforderungen. + DatabaseSettingsWidgetEncryption @@ -2168,6 +2255,50 @@ aus der Datenbank entfernt. Autosave delay since last change checkbox Verzögerung beim automatischen Speichern seit der letzten Änderung (Checkbox) + + Public Database Metadata + Öffentliche Datenbank-Metadaten + + + Warning: the following settings are not encrypted. + Warnung: Die folgenden Einstellungen sind nicht verschlüsselt. + + + Display name: + Anzeigename: + + + Publically visible display name used on the unlock dialog + Öffentlich sichtbarer Anzeigename, der im Entsperrdialog verwendet wird + + + Database public display name + Öffentlicher Anzeigename der Datenbank + + + Display color: + Anzeigefarbe: + + + Publically visible color used on the unlock dialog + Öffentlich sichtbare Farbe, die im Entsperrdialog verwendet wird + + + Database public display color chooser + Öffentliche Anzeigefarbwahl der Datenbank + + + Clear + Löschen + + + Display icon: + Anzeigesymbol: + + + Select Database Icon + Datenbanksymbol auswählen + DatabaseSettingsWidgetKeeShare @@ -2263,6 +2394,141 @@ aus der Datenbank entfernt. Beschreibungsfeld der Datenbank + + DatabaseSettingsWidgetRemote + + Sync Commands + Synchronisierungsbefehle + + + Remove + Entfernen + + + Command Settings + Befehlseinstellungen + + + Name + Name + + + Save + Speichern + + + Download + Herunterladen + + + Command: + Befehl: + + + Download command field + Feld für den Download-Befehl + + + e.g.: "sftp user@hostname" or "scp user@hostname:DatabaseOnRemote.kdbx {TEMP_DATABASE}" + z. B.: „sftp user@hostname“ or „scp user@hostname:DatabaseOnRemote.kdbx {TEMP_DATABASE}“ + + + Input: + Eingabe: + + + Download input field + Eingabefeld für den Download + + + Upload + Hochladen + + + Upload command field + Feld für den Upload-Befehl + + + e.g.: "sftp user@hostname" or "scp {TEMP_DATABASE} user@hostname:DatabaseOnRemote.kdbx" + z. B.: „sftp user@hostname“ oder „scp {TEMP_DATABASE} user@hostname:DatabaseOnRemote.kdbx“ + + + Upload input field + Eingabefeld für den Upload + + + Name cannot be empty. + Der Name darf nicht leer sein. + + + Test + Test + + + Download command cannot be empty. + Der Download-Befehl darf nicht leer sein. + + + Download failed with error: %1 + Herunterladen fehlgeschlagen mit Fehler: %1 + + + Download finished, but file %1 could not be found. + Herunterladen beendet, aber Datei %1 konnte nicht gefunden werden. + + + Download successful. + Herunterladen erfolgreich. + + + Save Remote Settings + Ferneinstellungen speichern + + + You have unsaved changes. Do you want to save them? + Sie haben ungespeicherte Änderungen. Möchten Sie sie speichern? + + + e.g.: +get DatabaseOnRemote.kdbx {TEMP_DATABASE} +exit +--- +{TEMP_DATABASE} is used as placeholder to store the database in a temporary location +The command has to exit. In case of `sftp` as last command `exit` has to be sent + + z. B.: +get DatabaseOnRemote.kdbx {TEMP_DATABASE} +exit +--- +{TEMP_DATABASE} wird als Platzhalter verwendet, um die Datenbank an einem temporären Ort zu speichern +Der Befehl muss beendet werden. Im Falle von `sftp` muss als letzter Befehl `exit` gesendet werden + + + + e.g.: +put {TEMP_DATABASE} DatabaseOnRemote.kdbx +exit +--- +{TEMP_DATABASE} is used as placeholder to store the database in a temporary location +The command has to exit. In case of `sftp` as last command `exit` has to be sent + + z. B.: +put {TEMP_DATABASE} DatabaseOnRemote.kdbx +exit +--- +{TEMP_DATABASE} wird als Platzhalter verwendet, um die Datenbank an einem temporären Ort zu speichern +Der Befehl muss beendet werden. Im Falle von `sftp` muss als letzter Befehl `exit` gesendet werden + + + + Timeout: + Timeout: + + + seconds + Sekunden + + DatabaseTabWidget @@ -2336,6 +2602,11 @@ Das ist definitiv ein Programmfehler, bitte benachrichtigen Sie die Entwickler.< Database tab name modifier %1 [Gesperrt] + + %1 [Temporary] + Database tab name modifier + %1 [Temporär] + DatabaseWidget @@ -2460,26 +2731,6 @@ Save changes? File has changed Datei hat sich geändert - - The database file has changed. Do you want to load the changes? - Die Datenbank wurde verändert. Änderungen laden? - - - Merge Request - Anfrage zum Zusammenführen - - - The database file has changed and you have unsaved changes. -Do you want to merge your changes? - Die Datenbank wurde verändert, und Sie haben nicht gespeicherte Änderungen. -Möchten Sie Ihre Änderungen zusammenführen? - - - Could not open the new database file while attempting to autoreload. -Error: %1 - Datenbank konnte während der automatischen Aktualisierung nicht geöffnet werden. -Fehler: %1 - Disable safe saves? Sicheres Speichern deaktivieren? @@ -2508,7 +2759,7 @@ Sicheres Speichern deaktivieren und erneut versuchen? Save database backup - Datenbank-Backup speichern + Sicherungskopie der Datenbank speichern Empty recycle bin? @@ -2531,6 +2782,86 @@ Sicheres Speichern deaktivieren und erneut versuchen? Database tab name modifier %1 [Neue Datenbank] + + Remote Sync did not contain any download or upload commands. + Fernsynchronisierung enthielt keine Download- oder Upload-Befehle. + + + Remote sync '%1' completed successfully! + Fernsynchronisierung '%1' erfolgreich abgeschlossen! + + + Remote sync '%1' failed: %2 + Fernsynchronisierung '%1' fehlgeschlagen: %2 + + + Error while saving database %1: %2 + Fehler beim Speichern der Datenbank %1: %2 + + + Downloading... + Herunterladen… + + + Uploading... + Hochladen… + + + Syncing... + Synchronisieren… + + + Remove passkey from entry + Passkey aus Eintrag entfernen + + + Do you want to remove the passkey from this entry? + Möchten Sie den Passkey aus diesem Eintrag entfernen? + + + The database file "%1" was modified externally + Die Datenbankdatei „%1“ wurde extern geändert + + + Do you want to load the changes? + Möchten Sie die Änderungen laden? + + + Reload database + Datenbank neu laden + + + Reloading database… + Datenbank wird neu geladen… + + + Reload canceled + Neuladen abgebrochen + + + Reload successful + Neuladen erfolgreich abgeschlossen + + + Reload pending user action… + Anstehende Benutzeraktion neu laden… + + + The database file "%1" was modified externally.<br>How would you like to proceed?<br><br>Merge all changes<br>Ignore the changes on disk until save<br>Discard unsaved changes + Die Datenbankdatei „%1“ wurde extern geändert.<br>Wie möchten Sie vorgehen?<br><br>Alle Änderungen zusammenführen<br>Änderungen auf der Festplatte bis zum Speichern ignorieren<br>Nicht gespeicherte Änderungen verwerfen + + + The database file "%1" was modified externally.<br>How would you like to proceed?<br><br>Merge all changes then save<br>Overwrite the changes on disk<br>Discard unsaved changes + Die Datenbankdatei „%1“ wurde extern geändert.<br>Wie möchten Sie vorgehen?<br><br>Alle Änderungen zusammenführen und dann speichern<br>Änderungen auf der Festplatte überschreiben<br>Nicht gespeicherte Änderungen verwerfen + + + Database file overwritten. + Datenbankdatei überschrieben. + + + Database file on disk cannot be unlocked with current credentials.<br>Enter new credentials and/or present hardware key to continue. + Die Datenbankdatei auf der Festplatte kann mit den aktuellen Anmeldedaten nicht entsperrt werden. Geben Sie neue Zugangsdaten ein und/oder benutzen Sie den Hardwareschlüssel, um fortzufahren. + EditEntryWidget @@ -2582,10 +2913,6 @@ Sicheres Speichern deaktivieren und erneut versuchen? n/a - - - (encrypted) - (verschlüsselt) - Select private key Privaten Schlüssel auswählen @@ -2688,6 +3015,10 @@ Korrigieren? %n year(s) %n Jahre%n Jahr(e) + + Failed to decrypt SSH key, ensure password is correct. + Entschlüsselung des SSH-Schlüssels fehlgeschlagen. Stellen Sie sicher, dass das Passwort korrekt ist. + EditEntryWidgetAdvanced @@ -2859,18 +3190,10 @@ Korrigieren? Skip Auto-Submit for this entry Auto-Submit für diesen Eintrag überspringen - - Only send this setting to the browser for HTTP Auth dialogs. If enabled, normal login forms will not show this entry for selection. - Diese Einstellung wird nur bei HTTP-Authentifizierungsdialogen an den Browser gesendet. Wenn aktiviert, wird dieser Eintrag in normalen Anmeldeformularen nicht zur Auswahl angezeigt. - Use this entry only with HTTP Basic Auth Diesen Eintrag nur mit HTTP-Basisauthentifizierung verwenden - - Do not send this setting to the browser for HTTP Auth dialogs. If enabled, HTTP Auth dialogs will not show this entry for selection. - Diese Einstellung nicht für HTTP-Authentifizierungsdialoge an den Browser senden. Wenn aktiviert, wird dieser Eintrag in HTTP-Authentifizierungsdialogen nicht zur Auswahl angezeigt. - Do not use this entry with HTTP Basic Auth Diesen Eintrag nicht mit HTTP-Basisauthentifizierung verwenden @@ -2895,6 +3218,14 @@ Korrigieren? Additional URLs Zusätzliche URLs + + Only send this entry to the browser for HTTP Auth dialogs. If enabled, normal login forms will not show this entry for selection. + Sendet diesen Eintrag nur bei HTTP-Auth-Dialogen an den Browser. Wenn aktiviert, wird dieser Eintrag in normalen Anmeldeformularen nicht zur Auswahl angezeigt. + + + Do not send this entry to the browser for HTTP Auth dialogs. If enabled, HTTP Auth dialogs will not show this entry for selection. + Diesen Eintrag nicht an den Browser für HTTP-Auth-Dialoge senden. Wenn aktiviert, zeigen HTTP-Auth-Dialoge diesen Eintrag nicht zur Auswahl an. + EditEntryWidgetHistory @@ -3117,6 +3448,10 @@ Korrigieren? seconds Sekunden + + Clear agent + Agent löschen + EditGroupWidget @@ -3559,6 +3894,24 @@ Das kann dazu führen, dass die betroffenen Plugins nicht mehr richtig funktioni %1 - Clone %1 - Klon + + Passkey + Passkey + + + Invalid conversion type: %1 + Ungültiger Konvertierungstyp: %1 + + + Invalid conversion syntax: %1 + Ungültige Konvertierungssyntax: %1 + + + Invalid regular expression syntax %1 +%2 + Ungültige Syntax des regulären Ausdrucks %1 +%2 + EntryAttachments @@ -3567,6 +3920,21 @@ Das kann dazu führen, dass die betroffenen Plugins nicht mehr richtig funktioni Datei „%1“ kann nicht geöffnet werden + + EntryAttachmentsDialog + + Form + Formular + + + File name + Dateiname + + + File contents... + Dateiinhalt… + + EntryAttachmentsModel @@ -3604,14 +3972,6 @@ Das kann dazu führen, dass die betroffenen Plugins nicht mehr richtig funktioni Remove Entfernen - - Rename selected attachment - Ausgewählten Anhang umbenennen - - - Rename - Umbenennen - Open selected attachment Ausgewählten Anhang öffnen @@ -3727,6 +4087,18 @@ Would you like to overwrite the existing attachment? Anhang „%1“ existiert bereits. Existierenden Anhang überschreiben? + + New + Neu + + + Preview + Vorschau + + + Failed to preview an attachment: Attachment not found + Vorschau eines Anhangs konnte nicht angezeigt werden: Anhang nicht gefunden + EntryAttributesModel @@ -3925,6 +4297,10 @@ Existierenden Anhang überschreiben? Background Color Hintergrundfarbe + + Group Path + Gruppenpfad + EntryPreviewWidget @@ -4319,6 +4695,14 @@ Sie können den DuckDuckGo-Dienst unter „Anwendungseinstellungen → Sicherhei Url URL + + Could not load key file. + Schlüsseldatei konnte nicht geladen werden. + + + Could not open remote database. Password or key file may be incorrect. + Ferndatenbank konnte nicht geöffnet werden. Das Passwort oder die Schlüsseldatei ist möglicherweise falsch. + ImportWizardPageSelect @@ -4422,6 +4806,50 @@ Sie können den DuckDuckGo-Dienst unter „Anwendungseinstellungen → Sicherhei KeePass1 Database KeePass 1-Datenbank + + Proton Pass (.json) + Proton Pass (.json) + + + Proton Pass JSON Export + Proton Pass JSON exportieren + + + Temporary Database + Temporäre Datenbank + + + Command: + Befehl: + + + e.g.: "sftp user@hostname" or "scp user@hostname:DatabaseOnRemote.kdbx {TEMP_DATABASE}" + z. B.: „sftp user@hostname“ oder „scp user@hostname:DatabaseOnRemote.kdbx {TEMP_DATABASE}“ + + + Input: + Eingabe: + + + e.g.: +get DatabaseOnRemote.kdbx {TEMP_DATABASE} +exit +--- +{TEMP_DATABASE} is used as placeholder to store the database in a temporary location +The command has to exit. In case of `sftp` as last commend `exit` has to be sent + + z. B.: +get DatabaseOnRemote.kdbx {TEMP_DATABASE} +exit +--- +{TEMP_DATABASE} wird als Platzhalter verwendet, um die Datenbank an einem temporären Ort zu speichern +Der Befehl muss beendet werden. Im Falle von `sftp` muss als letzter Befehl `exit` gesendet werden + + + + Remote Database (.kdbx) + Ferndatenbank (.kdbx) + KMessageWidget @@ -5475,7 +5903,7 @@ Wollen Sie wirklich mit dieser Datei fortfahren? Save Database Backup… - Datenbank-Backup speichern… + Sicherungskopie der Datenbank speichern… Add key to SSH Agent @@ -5562,12 +5990,6 @@ Diese Version ist nicht für den Produktiveinsatz gedacht. Expect some bugs and minor issues, this version is meant for testing purposes. HINWEIS: Sie verwenden eine Vorabversion von KeePassXC. Rechnen Sie mit Fehlern und kleineren Problemen. Diese Version ist für Testzwecke gedacht. - - - WARNING: Your Qt version may cause KeePassXC to crash with an On-Screen Keyboard. -We recommend you use the AppImage available on our downloads page. - WARNUNG: Ihre Qt-Version kann zum Absturz von KeePassXC mit einer Bildschirmtastatur führen. -Wir empfehlen Ihnen, das AppImage zu verwenden, das auf unserer Download-Seite verfügbar ist. No Tags @@ -5641,6 +6063,10 @@ Wir empfehlen Ihnen, das AppImage zu verwenden, das auf unserer Download-Seite v Import Passkey Passkey importieren + + Remote S&ync… + Ferns&ynchronisierung… + Quit Application Anwendung beenden @@ -5745,6 +6171,10 @@ Wir empfehlen Ihnen, das AppImage zu verwenden, das auf unserer Download-Seite v Show Password Generator Passwortgenerator anzeigen + + Remove Passkey From Entry + Passkey aus Eintrag entfernen + Perform Auto-Type: {USERNAME} Auto-Type ausführen: {BENUTZERNAME} @@ -5827,7 +6257,7 @@ Wir empfehlen Ihnen, das AppImage zu verwenden, das auf unserer Download-Seite v Save Database Backup - Datenbank-Backup speichern + Sicherungskopie der Datenbank speichern SSH Agent: Add Key @@ -5843,43 +6273,43 @@ Wir empfehlen Ihnen, das AppImage zu verwenden, das auf unserer Download-Seite v Set Theme: Automatic - Design festlegen: Automatisch + Design festlegen: automatisch Set Theme: Light - Design festlegen: Hell + Design festlegen: hell Set Theme: Dark - Design festlegen: Dunkel + Design festlegen: dunkel Set Theme: Classic - Design festlegen: Klassisch + Design festlegen: klassisch Toggle Show Menubar - Menüleiste ausblenden + 'Menüleiste anzeigen' umschalten Toggle Show Toolbar - + 'Symbolleiste anzeigen' umschalten Toggle Show Preview Panel - Vorschau-Panel ausblenden + 'Vorschaupanel anzeigen' umschalten Toggle Always on Top - + 'Immer im Vordergrund' umschalten Toggle Hide Usernames - Benutzernamen verstecken + 'Benutzernamen verstecken' umschalten Toggle Hide Passwords - Passwörter verstecken + 'Passwörter verstecken' umschalten Export to XML @@ -5887,7 +6317,35 @@ Wir empfehlen Ihnen, das AppImage zu verwenden, das auf unserer Download-Seite v Toggle Allow Screen Capture - + 'Bildschirmaufnahme zulassen' umschalten + + + Show Group Panel + Gruppenpanel anzeigen + + + Toggle Show Group Panel + 'Gruppenpanel anzeigen' umschalten + + + Setup Remote Sync… + Fernsynchronisierung einrichten… + + + Password Generator + Passwortgenerator + + + E&xpire Entry… + Abge&laufener Eintrag… + + + Clear SSH Agent + SSH-Agent löschen + + + Clear all identities in ssh-agent + Alle Identitäten im SSH-Agent löschen @@ -6039,6 +6497,25 @@ Wir empfehlen Ihnen, das AppImage zu verwenden, das auf unserer Download-Seite v Bitte geben Sie den Namen und (optional) eine Beschreibung der neuen Datenbank ein: + + NewEntryAttachmentsDialog + + Attachment name cannot be empty + Name des Anhangs darf nicht leer sein + + + Attachment with the same name already exists + Anhang mit demselben Namen existiert bereits + + + Save attachment + Anhang speichern + + + New entry attachment + Neuer Eintragsanhang + + NixUtils @@ -6226,6 +6703,10 @@ Wir empfehlen Ihnen, das AppImage zu verwenden, das auf unserer Download-Seite v Unexpected EOF when writing private key Unerwartetes Dateiende beim Schreiben des privaten Schlüssels + + (encrypted) + (verschlüsselt) + OpenSSHKeyGenDialog @@ -6274,7 +6755,7 @@ Wir empfehlen Ihnen, das AppImage zu verwenden, das auf unserer Download-Seite v Export the following passkey entries. - + Die folgenden Passkey-Einträge exportieren. @@ -6348,15 +6829,15 @@ Möchten Sie sie überschreiben? Import the following passkey: - + Den folgenden Passkey importieren: Import the following passkey to this entry: - + Den folgenden Passkey in diesen Eintrag importieren: Default passkeys group (Imported Passkeys) - + Standard-Passkeys-Gruppe (importierte Passkeys) @@ -6379,25 +6860,27 @@ Möchten Sie sie überschreiben? Open passkey file - + Passkey-Datei öffnen Cannot import passkey - + Passkey kann nicht importiert werden Cannot import passkey file "%1". Data is missing. - + Passkey-Datei „%1“ kann nicht importiert werden. Es fehlen Daten. Cannot import passkey file "%1". The following data is missing: %2 - + Passkey-Datei „%1“ kann nicht importiert werden. +Die folgenden Daten fehlen: +%2 Cannot import passkey file "%1". Private key is missing or malformed. - + Passkey-Datei „%1“ kann nicht importiert werden. Privater Schlüssel fehlt oder ist beschädigt. @@ -6578,10 +7061,6 @@ The following data is missing: Also choose from: Auch wählen aus: - - Excluded characters: "0", "1", "l", "I", "O", "|", "﹒" - Ausgeschlossene Zeichen: „0“, „1“, „l“, „I“, „O“, „|“, „﹒“ - Exclude look-alike characters Gleichaussehende Zeichen ausschließen @@ -6606,10 +7085,6 @@ The following data is missing: Word Count: Wortanzahl: - - Character Count: - Zeichenanzahl: - Word Case: Groß-/Kleinschreibung: @@ -6622,10 +7097,6 @@ The following data is missing: Add custom wordlist Benutzerdefinierte Wortliste hinzufügen - - character - Zeichen - Close Schließen @@ -6732,6 +7203,22 @@ Möchten Sie diese überschreiben? Special Characters Sonderzeichen + + passwordLength + Passwortlänge + + + Characters: %1 + Zeichen: %1 + + + MIXED case + Groß- und Kleinbuchstaben + + + Excluded characters: "0", "1", "l", "I", "O", "|", "﹒", "B", "8", "G", "6" + Ausgeschlossene Zeichen: „0“, „1“, „l“, „I“, „O“, „|“, „﹒“, „B“, „8“, „G“, „6“ + PasswordWidget @@ -6799,6 +7286,21 @@ Möchten Sie diese überschreiben? Taste &Tab zwischen Zeichen drücken + + PreviewEntryAttachmentsDialog + + Preview entry attachment + Vorschau des Eintragsanhangs + + + No preview available + Keine Vorschau verfügbar + + + Image format not supported + Bildformat wird nicht unterstützt + + QMessageBox @@ -7477,10 +7979,6 @@ Möchten Sie diese überschreiben? Invalid word count %1 Ungültige Wortanzahl %1 - - The word list is too small (< 1000 items) - Die Wortliste ist zu kurz (< 1000 Einträge) - Title for the entry. Titel für diesen Eintrag. @@ -7611,7 +8109,7 @@ Möchten Sie diese überschreiben? Type: Unknown (%1) - Typ: Unbekannt (%1) + Typ: unbekannt (%1) Entropy %1 (%2) @@ -7625,10 +8123,6 @@ Möchten Sie diese überschreiben? Exit interactive mode. Interaktiven Modus beenden. - - Format to use when exporting. Available choices are 'xml' or 'csv'. Defaults to 'xml'. - Zu benutzendes Format für den Export. Verfügbare Optionen sind 'xml' oder 'csv'. Standard ist 'xml'. - Exports the content of a database to standard output in the specified format. Exportiert den Inhalt einer Datenbank im angegebenen Format auf die Standardausgabe. @@ -8217,18 +8711,6 @@ Kernel: %3 %4 file empty Datei leer - - malformed string - Ungültige Zeichenfolge - - - missing closing quote - Schließendes Anführungszeichen fehlt - - - %1: (row, col) %2,%3 - %1: (Zeile, Spalte) %2,%3 - AES 256-bit AES 256-Bit @@ -8674,13 +9156,89 @@ Diese Option ist veraltet, verwenden Sie stattdessen --set-key-file.Tastenkürzel - Unsupported KDF type, cannot decrypt json file - Nicht unterstützter KDF-Typ, kann JSON-Datei nicht entschlüsseln + Unknown passkeys error + Unbekannter Passkey-Fehler - Unknown passkeys error + Invalid KDF iterations, cannot decrypt json file + Ungültige KDF-Iterationen, JSON-Datei kann nicht entschlüsselt werden. + + + Unsupported format, ensure your Bitwarden export is password-protected + Nicht unterstütztes Format, stellen Sie sicher, dass Ihr Bitwarden-Export passwortgeschützt ist. + + + Only PBKDF and Argon2 are supported, cannot decrypt json file + Nur PBKDF und Argon2 werden unterstützt, JSON-Datei kann nicht entschlüsselt werden. + + + Reset Shortcuts + Tastenkürzel zurücksetzen + + + Double click an action to change its shortcut + Doppelklick auf eine Aktion, um das Tastenkürzel zu ändern + + + Filter... + Filtern… + + + Shortcut Conflict + Tastenkürzelkonflikt + + + Shortcut %1 conflicts with '%2'. Overwrite shortcut? + Tastenkürzel %1 steht im Konflikt mit '%2'. Tastenkürzel überschreiben? + + + Cannot generate valid passphrases because the wordlist is too short + Es können keine gültigen Passphrasen erzeugt werden, da die Wortliste zu kurz ist + + + Encrypted files are not supported. + Verschlüsselte Dateien werden nicht unterstützt. + + + Proton Pass Import + Proton Pass importieren + + + Delete plugin data? + Plugin-Daten löschen? + + + Delete plugin data from Entry(s)? + Plugin-Daten aus Eintrag löschen?Plugin-Daten aus Einträgen löschen? + + + Passkey + Passkey + + + Format to use when exporting. Available choices are 'xml', 'csv' or 'html'. Defaults to 'xml'. + Für den Export zu verwendendes Format. Zur Auswahl stehen „xml“, „csv“ oder „html“. Standard ist „xml“. + + + start minimized to the system tray + Minimiert in der Taskleiste starten + + + malformed string, possible unescaped delimiter + + missing closing delimiter + + + + %1, row: %2, column: %3 + + + + Tags + Tags + QtIOCompressor @@ -8716,6 +9274,37 @@ Diese Option ist veraltet, verwenden Sie stattdessen --set-key-file.Interner Fehler in zlib: + + RemoteHandler + + Command `%1` did not finish in time. Process was killed. + Der Befehl `%1` wurde nicht rechtzeitig beendet. Der Prozess wurde beendet. + + + Failed to upload merged database. Command `%1` did not finish in time. Process was killed. + Das Hochladen der zusammengeführten Datenbank ist fehlgeschlagen. Der Befehl `%1` wurde nicht rechtzeitig beendet. Prozess wurde beendet. + + + Invalid download parameters provided. + Ungültige Download-Parameter angegeben. + + + Command `%1` failed to download database. + Der Befehl `%1` ist beim Herunterladen der Datenbank fehlgeschlagen. + + + Invalid database pointer or upload parameters provided. + Ungültiger Datenbankzeiger oder ungültige Upload-Parameter angegeben. + + + Command `%1` exited with status code: %2 + Der Befehl `%1` wurde mit Statuscode beendet: %2 + + + Failed to upload merged database. Command `%1` exited with status code: %2 + Das Hochladen der zusammengeführten Datenbank ist fehlgeschlagen. Der Befehl `%1` wurde mit Statuscode beendet: %2 + + ReportsWidgetBrowserStatistics @@ -8782,6 +9371,10 @@ Diese Option ist veraltet, verwenden Sie stattdessen --set-key-file.Exclude from reports Von Berichten ausschließen + + Expire Entry(s)… + Abgelaufener Eintrag…Abgelaufene Einträge… + Only show entries that have a URL Nur Einträge anzeigen, die eine URL enthalten @@ -8798,36 +9391,33 @@ Diese Option ist veraltet, verwenden Sie stattdessen --set-key-file. (Expired) (abgelaufen) + + Delete plugin data from Entry(s)… + Plugin-Daten aus Eintrag löschen…Plugin-Daten aus Einträgen löschen… + ReportsWidgetHealthcheck - Hover over reason to show additional details. Double-click entries to edit. - Für weitere Informationen mit der Maus über den Grund fahren. Doppelklick auf Einträge zum Bearbeiten. + Show expired entries + Abgelaufene Einträge anzeigen - Bad - Password quality - Sehr schlecht + (Expired) + (abgelaufen) + + + Hover over reason to show additional details. Double-click entries to edit. + Für weitere Informationen mit der Maus über den Grund fahren. Doppelklick auf Einträge zum Bearbeiten. Bad — password must be changed Sehr schlecht — Passwort muss geändert werden - - Poor - Password quality - Schlecht - Poor — password should be changed Schlecht — Passwort sollte geändert werden - - Weak - Password quality - Schwach - Weak — consider changing the password Schwach — Passwortänderung sollte erwogen werden @@ -8876,18 +9466,14 @@ Diese Option ist veraltet, verwenden Sie stattdessen --set-key-file.Exclude from reports Von Berichten ausschließen - - Show expired entries - Abgelaufene Einträge anzeigen + + Expire Entry(s)… + Abgelaufener Eintrag…Abgelaufene Einträge… Show entries that have been excluded from reports Einträge anzeigen, die von Berichten ausgeschlossen wurden - - (Expired) - (abgelaufen) - ReportsWidgetHibp @@ -8983,16 +9569,20 @@ Diese Option ist veraltet, verwenden Sie stattdessen --set-key-file.Exclude from reports Von Berichten ausschließen + + Expire Entry(s)… + Abgelaufener Eintrag…Abgelaufene Einträge… + ReportsWidgetPasskeys Export - Export + Exportieren… Import - Importieren + Importieren… List of entry URLs @@ -9044,11 +9634,11 @@ Diese Option ist veraltet, verwenden Sie stattdessen --set-key-file. Please wait, list of entries with passkeys is being updated… - + Bitte warten Sie, die Liste der Einträge mit Passkeys wird gerade aktualisiert… No entries with passkeys. - + Keine Einträge mit Passkeys. @@ -9224,6 +9814,14 @@ Diese Option ist veraltet, verwenden Sie stattdessen --set-key-file.No agent running, cannot list identities. Kein Agent ausgeführt, kann keine Identitäten auflisten. + + Failed to remove all SSH identities from agent. + Das Entfernen aller SSH-Identitäten vom Agent ist fehlgeschlagen. + + + All SSH identities removed from agent. + Alle SSH-Identitäten wurden vom Agent entfernt. + SearchHelpWidget @@ -9297,7 +9895,7 @@ Diese Option ist veraltet, verwenden Sie stattdessen --set-key-file. Search (%1)… Search placeholder text, %1 is the keyboard shortcut - Suchen (%1) … + Suchen (%1)… Case sensitive @@ -9402,7 +10000,7 @@ Diese Option ist veraltet, verwenden Sie stattdessen --set-key-file. <html><head/><body><p>This improves compatibility with certain applications which search for password without unlocking the database first.</p><p>But enabling this may also crash the client if the database can not be unlocked within a certain timeout. (Usually 25s, but may be a different value set in applications.) </p></body></html> - <html><head/><body><p>Dies verbessert die Kompatibilität mit bestimmten Anwendungen, die nach dem Passwort suchen, ohne die Datenbank vorher zu entsperren.</p><p>Die Aktivierung dieser Option kann jedoch auch zum Absturz des Clients führen, wenn die Datenbank nicht innerhalb einer bestimmten Zeitspanne entsperrt werden kann. (In der Regel 25s, kann aber auch ein anderer Wert sein, der in den Anwendungen eingestellt ist.) </p></body></html> + <html><head/><body><p>Dies verbessert die Kompatibilität mit bestimmten Anwendungen, die nach dem Passwort suchen, ohne die Datenbank vorher zu entsperren.</p><p>Die Aktivierung dieser Option kann jedoch auch zum Absturz des Clients führen, wenn die Datenbank nicht innerhalb einer bestimmten Zeitspanne entsperrt werden kann. (In der Regel 25 s, kann aber auch ein anderer Wert sein, der in den Anwendungen eingestellt ist.) </p></body></html> @@ -9509,29 +10107,6 @@ Diese Option ist veraltet, verwenden Sie stattdessen --set-key-file.Export in %1 - - ShortcutSettingsWidget - - Double click an action to change its shortcut - Doppelklick auf eine Aktion, um das Tastenkürzel zu ändern - - - Shortcut Conflict - Tastenkürzelkonflikt - - - Filter... - Filtern… - - - Shortcut %1 conflicts with '%2'. Overwrite shortcut? - Tastenkürzel %1 steht im Konflikt mit '%2'. Tastenkürzel überschreiben? - - - Reset Shortcuts - Tastenkürzel zurücksetzen - - TagModel @@ -9820,14 +10395,18 @@ Beispiel: JBSWY3DPEHPK3PXP No hardware keys detected Keine Hardwareschlüssel erkannt - - <p>If you own a <a href="https://www.yubico.com/">YubiKey</a> or <a href="https://onlykey.io">OnlyKey</a>, you can use it for additional security.</p><p>The key requires one of its slots to be programmed as <a href="https://docs.yubico.com/yesdk/users-manual/application-otp/challenge-response.html">HMAC-SHA1 Challenge-Response</a>.</p> - <p>Wenn Sie einen <a href="https://www.yubico.com/">YubiKey</a> oder <a href="https://onlykey.io">OnlyKey</a> besitzen, können Sie ihn für zusätzliche Sicherheit verwenden.</p><p>Für den Schlüssel muss einer seiner Steckplätze als <a href="https://docs.yubico.com/yesdk/users-manual/application-otp/challenge-response.html">HMAC-SHA1 Challenge-Response</a> programmiert werden.</p> - Refresh hardware keys Hardwareschlüssel aktualisieren + + <p>If you own a <a href="https://www.yubico.com/">YubiKey</a> or <a href="https://onlykey.io">OnlyKey</a>, you can use it for additional security.</p><p>The key requires one of its slots to be programmed with <a href="https://keepassxc.org/docs/#faq-yubikey-howto">Challenge-Response</a>.</p> + <p>Wenn Sie einen <a href="https://www.yubico.com/">YubiKey</a> oder <a href="https://onlykey.io">OnlyKey</a> besitzen, können Sie ihn für zusätzliche Sicherheit verwenden.</p><p>Dazu muss einer seiner Slots als <a href="https://keepassxc.org/docs/#faq-yubikey-howto">Challenge-Response</a> programmiert sein.</p> + + + Hardware keys found, but no slots are configured + Hardwareschlüssel gefunden, es sind aber keine Slots konfiguriert + YubiKeyInterfacePCSC diff --git a/share/translations/keepassxc_el.ts b/share/translations/keepassxc_el.ts index c4c5c7301..bc7e202a5 100644 --- a/share/translations/keepassxc_el.ts +++ b/share/translations/keepassxc_el.ts @@ -217,18 +217,50 @@ You must restart the application to set the new language. Would you like to restart now? Πρέπει να επανεκκινήσετε την εφαρμογή για να οριστεί η νέα γλώσσα. Θέλετε να κάνετε επανεκκίνηση τώρα; - - Reset Settings? - Επαναφορά Ρυθμίσεων; - - - Are you sure you want to reset all general and security settings to default? - Είστε βέβαιοι ότι θέλετε να επαναφέρετε όλες τις γενικές και ασφαλείας ρυθμίσεις στις προεπιλογές; - Select backup storage directory Επιλογή καταλόγου αποθήκευσης αντιγράφων ασφαλείας + + Confirm Reset + + + + Are you sure you want to reset all settings to default? + + + + Import KeePassXC Settings + + + + Failed to import settings from %1, not a valid settings file. + + + + Export KeePassXC Settings + + + + Small + + + + Normal + + + + Medium + + + + Large + + + + Custom + + ApplicationSettingsWidgetGeneral @@ -280,25 +312,6 @@ Include beta releases when checking for updates Συμπεριλάβετε εκδόσεις beta κατά τον έλεγχο για ενημερώσεις - - On database unlock, show entries that - Στο ξεκλείδωμα της βάσης δεδομένων, εμφανίστε τις καταχωρήσεις που - - - have expired - On database unlock, show entries that... - έχουν λήξει - - - days - On database unlock, show entries that will expire within %1 days - ημέρες - - - will expire within - On database unlock, show entries that... - θα λήξουν εντός - File Management Διαχείριση αρχείων @@ -323,22 +336,10 @@ Backup database file before saving Δημιουργία αντίγραφου ασφαλείας του αρχείου της βάσης δεδομένων πριν την αποθήκευση - - Backup destination - Προορισμός αντιγράφων ασφαλείας - - - Specifies the database backup file location. Occurrences of "{DB_FILENAME}" are replaced with the filename of the saved database without extension. {TIME:<format>} is replaced with the backup time, see https://doc.qt.io/qt-5/qdatetime.html#toString. <format> defaults to format string "dd_MM_yyyy_hh-mm-ss". - Καθορίζει τη θέση του αρχείου αντιγράφων ασφαλείας της βάσης δεδομένων. Οι εμφανίσεις του "{ΒΔ_ΟΝΟΜΑ ΑΡΧΕΙΟΥ}" αντικαθίστανται με το όνομα αρχείου της αποθηκευμένης βάσης δεδομένων χωρίς επέκταση. {ΩΡΑ:<format>} αντικαθίσταται με το χρόνο δημιουργίας αντιγράφων ασφαλείας, ανατρέξτε https://doc.qt.io/qt-5/qdatetime.html#toString. <format> Προεπιλογές για τη μορφοποίηση συμβολοσειράς "dd_MM_yyyy_hh mm-ss". - {DB_FILENAME}.old.kdbx {ΒΔ_ΟΝΟΜΑ ΑΡΧΕΙΟΥ}.old.kdbx - - Choose... - Επιλογή... - Use alternative saving method (may solve problems with Dropbox, Google Drive, GVFS, etc.) Χρήση εναλλακτικής μεθόδου αποθήκευσης (μπορεί να επιλύσει προβλήματα με το Dropbox, το Google Drive, GVFS κ.λπ.) @@ -505,6 +506,71 @@ Remember last typed entry for: Να θυμάστε την τελευταία πληκτρολογημένη καταχώρηση για: + + On database unlock, show entries that will expire within + + + + On database unlock, show entries that will expire within + + + + days + number of days warning for password expiration + ημέρες + + + Destination format: + + + + <html><head/><body><p><span style=" font-weight:600;">{DB_FILENAME}</span> is replaced with the filename of the saved database without extension</p><p><span style=" font-weight:600;">{TIME:&lt;format&gt;}</span> is replaced with the specified time format (default: dd_MM_yyyy_hh-mm-ss)</p><p>See the User Guide for more details</p></body></html> + + + + Choose folder... + + + + Show confirmation before moving entries to recycle bin + + + + Copy data on double clicking field in entry view + + + + Show toolbar + Εμφάνιση γραμμής εργαλείων + + + Show the menu bar by pressing the Alt key + + + + Show menubar + + + + Import settings… + + + + Export settings… + + + + Open browser on double clicking URL field in entry view + + + + Font size: + + + + Font size selection + + ApplicationSettingsWidgetSecurity @@ -570,18 +636,6 @@ Hide passwords in the entry preview panel Απόκρυψη κωδικών πρόσβασης στο πάνελ προεπισκόπησης καταχώρησης - - Hide entry notes by default - Να αποκρύπτονται εξ ορισμού οι σημειώσεις καταχωρήσεων - - - Move entries to recycle bin without confirmation - Μετακίνηση καταχωρήσεων στον Κάδο Ανακύκλωσης χωρίς επιβεβαίωση - - - Enable double click to copy the username/password entry columns - Ενεργοποίηση διπλού κλικ για αντιγραφή των στηλών εισαγωγής ονόματος χρήστη/κωδικού πρόσβασης - Privacy Ιδιωτικότητα @@ -594,6 +648,18 @@ Hide TOTP in the entry preview panel Απόκρυψη TOTP στον πίνακα προεπισκόπησης καταχώρησης + + Lock databases when switching user + + + + Lock Options + + + + Hide notes in the entry preview panel + + AutoType @@ -641,20 +707,6 @@ Entry does not have attribute for PICKCHARS: %1 Η καταχώρηση δεν έχει χαρακτηριστικό για PICKCHARS: %1 - - Invalid conversion type: %1 - Μη έγκυρος τύπος μετατροπής: %1 - - - Invalid conversion syntax: %1 - Μη έγκυρη σύνταξη μετατροπής: %1 - - - Invalid regular expression syntax %1 -%2 - Μη έγκυρη σύνταξη κανονικής έκφρασης % 1 -%2 - Invalid placeholder: %1 Μη έγκυρο σύμβολο υποκατάστασης: %1 @@ -1022,10 +1074,6 @@ Do you want to overwrite the passkey in %1 - %2? General Γενικά - - Browsers installed as snaps are currently not supported. - Προς το παρόν δεν υποστηρίζονται προγράμματα περιήγησης που έχουν εγκατασταθεί ως snaps. - Enable integration for these browsers: Ενεργοποίηση της ενσωμάτωσης για αυτά τα προγράμματα περιήγησης: @@ -1197,18 +1245,6 @@ Do you want to overwrite the passkey in %1 - %2? Custom extension ID Αναγνωριστικό προσαρμοσμένης επέκτασης - - Due to Snap sandboxing, you must run a script to enable browser integration.<br />You can obtain this script from %1 - Λόγω του Snap sandboxing, πρέπει να εκτελέσετε ένα σενάριο για να ενεργοποιήσετε την ενσωμάτωση του προγράμματος περιήγησης.<br />Μπορείτε να αποκτήσετε αυτό το σενάριο από το %1 - - - KeePassXC-Browser is needed for the browser integration to work. <br />Download it for %1 and %2 and %3. %4 - Απαιτείται το KeePassXC-Browser για να λειτουργήσει η ενσωμάτωση του προγράμματος περιήγησης. <br />Κατεβάστε το για %1 και %2 και %3. %4 - - - Please see special instructions for browser extension use below - Δείτε παρακάτω ειδικές οδηγίες για τη χρήση της επέκτασης προγράμματος περιήγησης - Executable Files Εκτελέσιμα Αρχεία @@ -1257,6 +1293,14 @@ Do you want to overwrite the passkey in %1 - %2? Allow using localhost with passkeys + + KeePassXC-Browser is needed for the browser integration to work. <br />Download it for %1 and %2 and %3. + + + + Browsers installed using Snap or Flatpak are not supported with exception to Firefox installed using Snap. + + CloneDialog @@ -1399,6 +1443,19 @@ Do you want to overwrite the passkey in %1 - %2? Imported from CSV file: %1 Εισήχθη από αρχείο CSV: %1 + + No Title Selected + + + + No title column was selected, entries will be hard to tell apart. +Are you sure you want to import? + + + + Tags + Ετικέτες + CsvParserModel @@ -1462,6 +1519,14 @@ Backup database located at %2 Recycle Bin Κάδος Ανακύκλωσης + + Database file read error. + + + + No file path was provided. + + DatabaseOpenDialog @@ -1610,14 +1675,6 @@ To prevent this error from appearing, you must go to "Database Settings / S <p>In addition to a password, you can use a secret file to enhance the security of your database. This file can be generated in your database's security settings.</p><p>This is <strong>not</strong> your *.kdbx database file!</p> <p>Εκτός από έναν κωδικό πρόσβασης, μπορείτε να χρησιμοποιήσετε ένα μυστικό αρχείο για να βελτιώσετε την ασφάλεια της βάσης δεδομένων σας. Αυτό το αρχείο μπορεί να δημιουργηθεί στις ρυθμίσεις ασφαλείας της βάσης δεδομένων σας.</p> <p>Αυτό <strong>δεν</strong> είναι το αρχείο βάσης δεδομένων *.kdbx!</p> - - Click to add a key file. - Κάντε κλικ για να προσθέσετε ένα κλειδί αρχείου. - - - <a href="#" style="text-decoration: underline">I have a key file</a> - <a href="#" style="text-decoration: underline">Έχω ένα αρχείο κλειδί</a> - Use hardware key [Serial: %1] Χρησιμοποιήστε κλειδί υλικού [Serial: %1] @@ -1654,6 +1711,18 @@ Are you sure you want to continue with this file?. Refresh Hardware Keys Ανανέωση Κλειδιών Υλικού + + Click to add a key file. + Κάντε κλικ για να προσθέσετε ένα κλειδί αρχείου. + + + <a href="#" style="text-decoration: underline">I have a key file</a> + <a href="#" style="text-decoration: underline">Έχω ένα αρχείο κλειδί</a> + + + Hardware keys found, but no slots are configured. + + DatabaseSettingWidgetMetaData @@ -1688,6 +1757,22 @@ Are you sure you want to continue with this file?. Maintenance Συντήρηση + + KeeShare + KeeShare + + + Secret Service Integration + Ενσωμάτωση Secret Service + + + Remote Sync + + + + Database Settings: %1 + + DatabaseSettingsWidgetBrowser @@ -1858,14 +1943,14 @@ Are you sure you want to continue without a password? Weak password Αδύναμος κωδικός πρόσβασης - - You must enter a stronger password to protect your database. - Πρέπει να εισάγετε έναν ισχυρότερο κωδικό πρόσβασης για να προστατεύσετε τη βάση δεδομένων σας. - This is a weak password! For better protection of your secrets, you should choose a stronger password. Αυτός είναι ένας αδύναμος κωδικός πρόσβασης! Για καλύτερη προστασία των μυστικών σας, θα πρέπει να επιλέξετε έναν ισχυρότερο κωδικό πρόσβασης. + + The provided password does not meet the minimum quality requirement. + + DatabaseSettingsWidgetEncryption @@ -2167,6 +2252,50 @@ removed from the database. Autosave delay since last change checkbox Καθυστέρηση αυτόματης αποθήκευσης από την τελευταία αλλαγή του checkbox + + Public Database Metadata + + + + Warning: the following settings are not encrypted. + + + + Display name: + + + + Publically visible display name used on the unlock dialog + + + + Database public display name + + + + Display color: + + + + Publically visible color used on the unlock dialog + + + + Database public display color chooser + + + + Clear + Καθαρισμός + + + Display icon: + + + + Select Database Icon + + DatabaseSettingsWidgetKeeShare @@ -2262,6 +2391,129 @@ removed from the database. Πεδίο περιγραφής βάσης δεδομένων + + DatabaseSettingsWidgetRemote + + Sync Commands + + + + Remove + Αφαίρεση + + + Command Settings + + + + Name + Όνομα + + + Save + Αποθήκευση + + + Download + + + + Command: + + + + Download command field + + + + e.g.: "sftp user@hostname" or "scp user@hostname:DatabaseOnRemote.kdbx {TEMP_DATABASE}" + + + + Input: + + + + Download input field + + + + Upload + + + + Upload command field + + + + e.g.: "sftp user@hostname" or "scp {TEMP_DATABASE} user@hostname:DatabaseOnRemote.kdbx" + + + + Upload input field + + + + Name cannot be empty. + + + + Test + + + + Download command cannot be empty. + + + + Download failed with error: %1 + + + + Download finished, but file %1 could not be found. + + + + Download successful. + + + + Save Remote Settings + + + + You have unsaved changes. Do you want to save them? + + + + e.g.: +get DatabaseOnRemote.kdbx {TEMP_DATABASE} +exit +--- +{TEMP_DATABASE} is used as placeholder to store the database in a temporary location +The command has to exit. In case of `sftp` as last command `exit` has to be sent + + + + + e.g.: +put {TEMP_DATABASE} DatabaseOnRemote.kdbx +exit +--- +{TEMP_DATABASE} is used as placeholder to store the database in a temporary location +The command has to exit. In case of `sftp` as last command `exit` has to be sent + + + + + Timeout: + + + + seconds + δευτερόλεπτα + + DatabaseTabWidget @@ -2335,6 +2587,11 @@ This is definitely a bug, please report it to the developers. Database tab name modifier %1 [Κλειδωμένη] + + %1 [Temporary] + Database tab name modifier + + DatabaseWidget @@ -2458,26 +2715,6 @@ Save changes? File has changed Το αρχείο έχει αλλάξει - - The database file has changed. Do you want to load the changes? - Το αρχείο βάσης δεδομένων έχει αλλάξει. Θέλετε να φορτώσετε τις αλλαγές; - - - Merge Request - Αίτημα Συγχώνευσης - - - The database file has changed and you have unsaved changes. -Do you want to merge your changes? - Το αρχείο βάσης δεδομένων έχει αλλάξει και έχετε μη αποθηκευμένες αλλαγές. -Θέλετε να συγχωνεύσετε τις αλλαγές σας; - - - Could not open the new database file while attempting to autoreload. -Error: %1 - Δεν ήταν δυνατό το άνοιγμα του νέου αρχείου βάσης δεδομένων κατά την προσπάθεια αυτόματης φόρτωσης. -Σφάλμα: %1 - Disable safe saves? Απενεργοποίηση ασφαλών αποθηκεύσεων; @@ -2529,6 +2766,86 @@ Disable safe saves and try again? Database tab name modifier %1 [Νέα Βάση Δεδομένων] + + Remote Sync did not contain any download or upload commands. + + + + Remote sync '%1' completed successfully! + + + + Remote sync '%1' failed: %2 + + + + Error while saving database %1: %2 + + + + Downloading... + Λήψη... + + + Uploading... + + + + Syncing... + + + + Remove passkey from entry + + + + Do you want to remove the passkey from this entry? + + + + The database file "%1" was modified externally + + + + Do you want to load the changes? + + + + Reload database + + + + Reloading database… + + + + Reload canceled + + + + Reload successful + + + + Reload pending user action… + + + + The database file "%1" was modified externally.<br>How would you like to proceed?<br><br>Merge all changes<br>Ignore the changes on disk until save<br>Discard unsaved changes + + + + The database file "%1" was modified externally.<br>How would you like to proceed?<br><br>Merge all changes then save<br>Overwrite the changes on disk<br>Discard unsaved changes + + + + Database file overwritten. + + + + Database file on disk cannot be unlocked with current credentials.<br>Enter new credentials and/or present hardware key to continue. + + EditEntryWidget @@ -2580,10 +2897,6 @@ Disable safe saves and try again? n/a n/a - - (encrypted) - (κρυπτογραφημένο) - Select private key Επιλέξτε ιδιωτικό κλειδί @@ -2686,6 +2999,10 @@ Would you like to correct it? %n year(s) %n χρόνος%n χρόνια + + Failed to decrypt SSH key, ensure password is correct. + + EditEntryWidgetAdvanced @@ -2857,18 +3174,10 @@ Would you like to correct it? Skip Auto-Submit for this entry Παράλειψη Αυτόματης Υποβολής για αυτήν την καταχώρηση - - Only send this setting to the browser for HTTP Auth dialogs. If enabled, normal login forms will not show this entry for selection. - Μόνο αποστολή αυτής της ρύθμισης στο πρόγραμμα περιήγησης για παράθυρα διαλόγου HTTP Auth. Εάν ενεργοποιηθεί, οι κανονικές φόρμες σύνδεσης δεν θα εμφανίζουν αυτήν την καταχώρηση για επιλογή. - Use this entry only with HTTP Basic Auth Χρήση αυτής της καταχώρησης μόνο με HTTP Basic Auth - - Do not send this setting to the browser for HTTP Auth dialogs. If enabled, HTTP Auth dialogs will not show this entry for selection. - Μην στέλνετε αυτήν τη ρύθμιση στο πρόγραμμα περιήγησης για παράθυρα διαλόγου HTTP Auth. Εάν είναι ενεργοποιημένο, τα παράθυρα διαλόγου HTTP Auth δεν θα εμφανίζουν αυτήν την καταχώρηση για επιλογή. - Do not use this entry with HTTP Basic Auth Μην χρησιμοποιείτε αυτήν την καταχώρηση με το HTTP Basic Auth @@ -2893,6 +3202,14 @@ Would you like to correct it? Additional URLs + + Only send this entry to the browser for HTTP Auth dialogs. If enabled, normal login forms will not show this entry for selection. + + + + Do not send this entry to the browser for HTTP Auth dialogs. If enabled, HTTP Auth dialogs will not show this entry for selection. + + EditEntryWidgetHistory @@ -3115,6 +3432,10 @@ Would you like to correct it? seconds δευτερόλεπτα + + Clear agent + + EditGroupWidget @@ -3557,6 +3878,24 @@ This may cause the affected plugins to malfunction. %1 - Clone %1 - Κλώνος + + Passkey + Passkey + + + Invalid conversion type: %1 + Μη έγκυρος τύπος μετατροπής: %1 + + + Invalid conversion syntax: %1 + Μη έγκυρη σύνταξη μετατροπής: %1 + + + Invalid regular expression syntax %1 +%2 + Μη έγκυρη σύνταξη κανονικής έκφρασης % 1 +%2 + EntryAttachments @@ -3565,6 +3904,21 @@ This may cause the affected plugins to malfunction. Δεν είναι δυνατό το άνοιγμα του αρχείου "%1" + + EntryAttachmentsDialog + + Form + Μορφή + + + File name + + + + File contents... + + + EntryAttachmentsModel @@ -3602,14 +3956,6 @@ This may cause the affected plugins to malfunction. Remove Κατάργηση - - Rename selected attachment - Μετονομασία επιλεγμένου συνημμένου - - - Rename - Μετονομασία - Open selected attachment Άνοιγμα επιλεγμένου συνημμένου @@ -3725,6 +4071,18 @@ Would you like to overwrite the existing attachment? Το συνημμένο "%1" υπάρχει ήδη. Θέλετε να αντικαταστήσετε το υπάρχον συνημμένο; + + New + + + + Preview + Προεπισκόπηση + + + Failed to preview an attachment: Attachment not found + + EntryAttributesModel @@ -3923,6 +4281,10 @@ Would you like to overwrite the existing attachment? Background Color Χρώμα Φόντου + + Group Path + + EntryPreviewWidget @@ -4317,6 +4679,14 @@ You can enable the DuckDuckGo website icon service in the security section of th Url Url + + Could not load key file. + + + + Could not open remote database. Password or key file may be incorrect. + + ImportWizardPageSelect @@ -4420,6 +4790,44 @@ You can enable the DuckDuckGo website icon service in the security section of th KeePass1 Database + + Proton Pass (.json) + + + + Proton Pass JSON Export + + + + Temporary Database + + + + Command: + + + + e.g.: "sftp user@hostname" or "scp user@hostname:DatabaseOnRemote.kdbx {TEMP_DATABASE}" + + + + Input: + + + + e.g.: +get DatabaseOnRemote.kdbx {TEMP_DATABASE} +exit +--- +{TEMP_DATABASE} is used as placeholder to store the database in a temporary location +The command has to exit. In case of `sftp` as last commend `exit` has to be sent + + + + + Remote Database (.kdbx) + + KMessageWidget @@ -5560,12 +5968,6 @@ This version is not meant for production use. Expect some bugs and minor issues, this version is meant for testing purposes. ΣΗΜΕΙΩΣΗ: Χρησιμοποιείτε μια έκδοση πριν από την κανονική κυκλοφορία του KeePassXC. Περιμένετε ορισμένα σφάλματα και μικρά ζητήματα, αυτή η έκδοση προορίζεται για σκοπούς δοκιμών. - - - WARNING: Your Qt version may cause KeePassXC to crash with an On-Screen Keyboard. -We recommend you use the AppImage available on our downloads page. - ΠΡΟΕΙΔΟΠΟΙΗΣΗ: Η έκδοση Qt ενδέχεται να προκαλέσει αιφνίδια διακοπή λειτουργίας του KeePassXC με Πληκτρολόγιο Οθόνης. -Σας συνιστούμε να χρησιμοποιήσετε το AppImage που είναι διαθέσιμο στη σελίδα λήψεων. No Tags @@ -5639,6 +6041,10 @@ We recommend you use the AppImage available on our downloads page. Import Passkey Εισαγωγή Passkey + + Remote S&ync… + + Quit Application Έξοδος Εφαρμογής @@ -5743,6 +6149,10 @@ We recommend you use the AppImage available on our downloads page. Show Password Generator Εμφάνιση Γεννήτριας Κωδικών Πρόσβασης + + Remove Passkey From Entry + + Perform Auto-Type: {USERNAME} Εκτέλεση Αυτόματης-Πληκτρολόγησης: {USERNAME} @@ -5887,6 +6297,34 @@ We recommend you use the AppImage available on our downloads page. Toggle Allow Screen Capture Εναλλαγή Επιτρεπόμενης Καταγραφής Οθόνης + + Show Group Panel + + + + Toggle Show Group Panel + + + + Setup Remote Sync… + + + + Password Generator + Γεννήτρια Κωδικών + + + E&xpire Entry… + + + + Clear SSH Agent + + + + Clear all identities in ssh-agent + + ManageDatabase @@ -6037,6 +6475,25 @@ We recommend you use the AppImage available on our downloads page. Συμπληρώστε το εμφανιζόμενο όνομα και μια προαιρετική περιγραφή για τη νέα σας βάση δεδομένων: + + NewEntryAttachmentsDialog + + Attachment name cannot be empty + + + + Attachment with the same name already exists + + + + Save attachment + Αποθήκευση συνημμένου + + + New entry attachment + + + NixUtils @@ -6224,6 +6681,10 @@ We recommend you use the AppImage available on our downloads page. Unexpected EOF when writing private key Μη αναμενόμενο EOF κατά τη σύνταξη ιδιωτικού κλειδιού + + (encrypted) + (κρυπτογραφημένο) + OpenSSHKeyGenDialog @@ -6576,10 +7037,6 @@ The following data is missing: Also choose from: Επιλέξτε επίσης από: - - Excluded characters: "0", "1", "l", "I", "O", "|", "﹒" - Εξαιρούμενοι χαρακτήρες: "0", "1", "l", "I", "O", "|", ".". - Exclude look-alike characters Εξαίρεση παρόμοιων χαρακτήρων @@ -6604,10 +7061,6 @@ The following data is missing: Word Count: Αριθμός Λέξεων: - - Character Count: - Αριθμός Χαρακτήρων: - Word Case: Κουτί Λέξεων: @@ -6620,10 +7073,6 @@ The following data is missing: Add custom wordlist Προσθήκη προσαρμοσμένης λίστας λέξεων - - character - χαρακτήρας - Close Κλείσιμο @@ -6730,6 +7179,22 @@ Do you want to overwrite it? Special Characters Ειδικοί χαρακτήρες + + passwordLength + + + + Characters: %1 + + + + MIXED case + + + + Excluded characters: "0", "1", "l", "I", "O", "|", "﹒", "B", "8", "G", "6" + + PasswordWidget @@ -6797,6 +7262,21 @@ Do you want to overwrite it? Πατήστε το πλήκτρο &Τab μεταξύ χαρακτήρων + + PreviewEntryAttachmentsDialog + + Preview entry attachment + + + + No preview available + + + + Image format not supported + + + QMessageBox @@ -7475,10 +7955,6 @@ Do you want to overwrite it? Invalid word count %1 Μη έγκυρος αριθμός λέξεων %1 - - The word list is too small (< 1000 items) - Η λίστα λέξεων είναι πολύ μικρή (< 1000 στοιχεία) - Title for the entry. Τίτλος για την καταχώρηση. @@ -7623,10 +8099,6 @@ Do you want to overwrite it? Exit interactive mode. Έξοδος από διαδραστική λειτουργία. - - Format to use when exporting. Available choices are 'xml' or 'csv'. Defaults to 'xml'. - Μορφή για χρήση κατά την εξαγωγή. Οι διαθέσιμες επιλογές είναι «xml» ή «csv». Προεπιλογή σε "xml". - Exports the content of a database to standard output in the specified format. Εξάγει το περιεχόμενο μιας βάσης δεδομένων σε τυπική έξοδο στην καθορισμένη μορφή. @@ -8215,18 +8687,6 @@ Kernel: %3 %4 file empty κενό αρχείο - - malformed string - παραμορφωμένο string - - - missing closing quote - Λείπει το τελείωμα αποσπάσματος - - - %1: (row, col) %2,%3 - %1: (γραμμή, στήλη) %2,%3 - AES 256-bit AES 256-bit @@ -8671,13 +9131,89 @@ This option is deprecated, use --set-key-file instead. Συντομεύσεις - Unsupported KDF type, cannot decrypt json file + Unknown passkeys error - Unknown passkeys error + Invalid KDF iterations, cannot decrypt json file + + Unsupported format, ensure your Bitwarden export is password-protected + + + + Only PBKDF and Argon2 are supported, cannot decrypt json file + + + + Reset Shortcuts + Επαναφορά Συντομεύσεων + + + Double click an action to change its shortcut + Κάντε διπλό κλικ σε μια ενέργεια για να αλλάξετε τη συντόμευσή της. + + + Filter... + Φίλτρο... + + + Shortcut Conflict + Διένεξη Συντομεύσεων + + + Shortcut %1 conflicts with '%2'. Overwrite shortcut? + Η συντόμευση %1 έρχεται σε διένεξη με την '%2'. Να αντικατασταθεί η συντόμευση; + + + Cannot generate valid passphrases because the wordlist is too short + + + + Encrypted files are not supported. + + + + Proton Pass Import + + + + Delete plugin data? + Διαγραφή δεδομένων πρόσθετου; + + + Delete plugin data from Entry(s)? + + + + Passkey + Passkey + + + Format to use when exporting. Available choices are 'xml', 'csv' or 'html'. Defaults to 'xml'. + + + + start minimized to the system tray + + + + malformed string, possible unescaped delimiter + + + + missing closing delimiter + + + + %1, row: %2, column: %3 + + + + Tags + Ετικέτες + QtIOCompressor @@ -8713,6 +9249,37 @@ This option is deprecated, use --set-key-file instead. Εσωτερικό σφάλμα zlib: + + RemoteHandler + + Command `%1` did not finish in time. Process was killed. + + + + Failed to upload merged database. Command `%1` did not finish in time. Process was killed. + + + + Invalid download parameters provided. + + + + Command `%1` failed to download database. + + + + Invalid database pointer or upload parameters provided. + + + + Command `%1` exited with status code: %2 + + + + Failed to upload merged database. Command `%1` exited with status code: %2 + + + ReportsWidgetBrowserStatistics @@ -8779,6 +9346,10 @@ This option is deprecated, use --set-key-file instead. Exclude from reports Εξαίρεση από αναφορές + + Expire Entry(s)… + + Only show entries that have a URL Εμφάνιση μόνο καταχωρίσεων που έχουν διεύθυνση URL @@ -8795,36 +9366,33 @@ This option is deprecated, use --set-key-file instead. (Expired) (Εχει λήξει) + + Delete plugin data from Entry(s)… + + ReportsWidgetHealthcheck - Hover over reason to show additional details. Double-click entries to edit. - Τοποθετήστε το δείκτη του ποντικιού για να εμφανίσετε επιπλέον λεπτομέρειες. Κάντε διπλό κλικ στις καταχωρήσεις για επεξεργασία. + Show expired entries + Εμφάνιση καταχωρήσεων που έχουν λήξει - Bad - Password quality - Κακός + (Expired) + (Εχει λήξει) + + + Hover over reason to show additional details. Double-click entries to edit. + Τοποθετήστε το δείκτη του ποντικιού για να εμφανίσετε επιπλέον λεπτομέρειες. Κάντε διπλό κλικ στις καταχωρήσεις για επεξεργασία. Bad — password must be changed κακός — ο κωδικός πρόσβασης πρέπει να αλλάξει - - Poor - Password quality - Φτωχός - Poor — password should be changed Φτωχός — ο κωδικός πρόσβασης πρέπει να αλλάξει - - Weak - Password quality - Αδύναμος - Weak — consider changing the password Αδύναμος — εξετάστε το ενδεχόμενο αλλαγής του κωδικού πρόσβασης @@ -8873,18 +9441,14 @@ This option is deprecated, use --set-key-file instead. Exclude from reports Εξαίρεση από αναφορές - - Show expired entries - Εμφάνιση καταχωρήσεων που έχουν λήξει + + Expire Entry(s)… + Show entries that have been excluded from reports Εμφάνιση καταχωρήσεων που έχουν εξαιρεθεί από τις αναφορές - - (Expired) - (Εχει λήξει) - ReportsWidgetHibp @@ -8980,6 +9544,10 @@ This option is deprecated, use --set-key-file instead. Exclude from reports Εξαίρεση από αναφορές + + Expire Entry(s)… + + ReportsWidgetPasskeys @@ -9221,6 +9789,14 @@ This option is deprecated, use --set-key-file instead. No agent running, cannot list identities. Κανένας agent δεν εκτελείται, δεν μπορεί να αναφέρει τις ταυτότητες. + + Failed to remove all SSH identities from agent. + + + + All SSH identities removed from agent. + + SearchHelpWidget @@ -9506,29 +10082,6 @@ This option is deprecated, use --set-key-file instead. Εξαγωγή σε %1 - - ShortcutSettingsWidget - - Double click an action to change its shortcut - Κάντε διπλό κλικ σε μια ενέργεια για να αλλάξετε τη συντόμευσή της. - - - Shortcut Conflict - Διένεξη Συντομεύσεων - - - Filter... - Φίλτρο... - - - Shortcut %1 conflicts with '%2'. Overwrite shortcut? - Η συντόμευση %1 έρχεται σε διένεξη με την '%2'. Να αντικατασταθεί η συντόμευση; - - - Reset Shortcuts - Επαναφορά Συντομεύσεων - - TagModel @@ -9818,11 +10371,15 @@ Example: JBSWY3DPEHPK3PXP Δεν εντοπίστηκαν hardware κλειδιά - <p>If you own a <a href="https://www.yubico.com/">YubiKey</a> or <a href="https://onlykey.io">OnlyKey</a>, you can use it for additional security.</p><p>The key requires one of its slots to be programmed as <a href="https://docs.yubico.com/yesdk/users-manual/application-otp/challenge-response.html">HMAC-SHA1 Challenge-Response</a>.</p> - <p>Εάν είστε ιδιοκτήτης ενός <a href="https://www.yubico.com/">YubiKey</a> ή <a href="https://onlykey.io">OnlyKey</a>, μπορείτε να το χρησιμοποιήσετε για πρόσθετη ασφάλεια.</p> <p>Το κλειδί απαιτεί μία από τις υποδοχές του να προγραμματιστεί ως <a href="https://docs.yubico.com/yesdk/users-manual/application-otp/challenge-response.html">HMAC-SHA1 Πρόκληση-Απόκριση</a>.</p> + Refresh hardware keys + - Refresh hardware keys + <p>If you own a <a href="https://www.yubico.com/">YubiKey</a> or <a href="https://onlykey.io">OnlyKey</a>, you can use it for additional security.</p><p>The key requires one of its slots to be programmed with <a href="https://keepassxc.org/docs/#faq-yubikey-howto">Challenge-Response</a>.</p> + + + + Hardware keys found, but no slots are configured diff --git a/share/translations/keepassxc_en.ts b/share/translations/keepassxc_en.ts index b23d7b082..16cd879b9 100644 --- a/share/translations/keepassxc_en.ts +++ b/share/translations/keepassxc_en.ts @@ -1,6 +1,6 @@ - + AboutDialog @@ -82,6 +82,10 @@ Details + + Your decision will be remembered for the duration while both the requesting client AND KeePassXC are running. + + Remember @@ -90,10 +94,6 @@ Allow Selected - - Your decision will be remembered for the duration while both the requesting client AND KeePassXC are running. - - Deny All && Future @@ -124,6 +124,10 @@ Use OpenSSH + + Use both agents + + SSH_AUTH_SOCK override @@ -152,10 +156,6 @@ SSH Agent connection is working! - - Use both agents - - ApplicationSettingsWidget @@ -171,6 +171,10 @@ Security + + This setting cannot be enabled when minimize on unlock is enabled. + + Access error for config file %1 @@ -215,20 +219,48 @@ You must restart the application to set the new language. Would you like to restart now? - - Reset Settings? - - - - Are you sure you want to reset all general and security settings to default? - - Select backup storage directory - This setting cannot be enabled when minimize on unlock is enabled. + Confirm Reset + + + + Are you sure you want to reset all settings to default? + + + + Import KeePassXC Settings + + + + Failed to import settings from %1, not a valid settings file. + + + + Export KeePassXC Settings + + + + Small + + + + Normal + + + + Medium + + + + Large + + + + Custom @@ -262,6 +294,10 @@ Remember previously used databases + + recent files + + Load previously open databases on startup @@ -278,25 +314,6 @@ Include beta releases when checking for updates - - On database unlock, show entries that - - - - have expired - On database unlock, show entries that... - - - - days - On database unlock, show entries that will expire within %1 days - - - - will expire within - On database unlock, show entries that... - - File Management @@ -321,22 +338,10 @@ Backup database file before saving - - Backup destination - - - - Specifies the database backup file location. Occurrences of "{DB_FILENAME}" are replaced with the filename of the saved database without extension. {TIME:<format>} is replaced with the backup time, see https://doc.qt.io/qt-5/qdatetime.html#toString. <format> defaults to format string "dd_MM_yyyy_hh-mm-ss". - - {DB_FILENAME}.old.kdbx - - Choose... - - Use alternative saving method (may solve problems with Dropbox, Google Drive, GVFS, etc.) @@ -414,6 +419,10 @@ Toolbar button style: + + Show passwords in color + + Use monospaced font for notes @@ -500,11 +509,68 @@ - recent files + On database unlock, show entries that will expire within - Show passwords in color + On database unlock, show entries that will expire within + + + + days + number of days warning for password expiration + + + + Destination format: + + + + <html><head/><body><p><span style=" font-weight:600;">{DB_FILENAME}</span> is replaced with the filename of the saved database without extension</p><p><span style=" font-weight:600;">{TIME:&lt;format&gt;}</span> is replaced with the specified time format (default: dd_MM_yyyy_hh-mm-ss)</p><p>See the User Guide for more details</p></body></html> + + + + Choose folder... + + + + Show confirmation before moving entries to recycle bin + + + + Copy data on double clicking field in entry view + + + + Show toolbar + + + + Show the menu bar by pressing the Alt key + + + + Show menubar + + + + Import settings… + + + + Export settings… + + + + Open browser on double clicking URL field in entry view + + + + Font size: + + + + Font size selection @@ -572,18 +638,6 @@ Hide passwords in the entry preview panel - - Hide entry notes by default - - - - Move entries to recycle bin without confirmation - - - - Enable double click to copy the username/password entry columns - - Privacy @@ -596,6 +650,29 @@ Hide TOTP in the entry preview panel + + Lock databases when switching user + + + + Lock Options + + + + Hide notes in the entry preview panel + + + + + AttachmentWidget + + Attachment Viewer + + + + Unknown attachment type + + AutoType @@ -640,16 +717,7 @@ - Invalid conversion type: %1 - - - - Invalid conversion syntax: %1 - - - - Invalid regular expression syntax %1 -%2 + Entry does not have attribute for PICKCHARS: %1 @@ -657,7 +725,7 @@ - Entry does not have attribute for PICKCHARS: %1 + Entry has invalid TOTP settings @@ -816,6 +884,10 @@ Ctrl+4 - Use Virtual Keyboard (Windows Only)</p> Disable for this site + + Undo + + BrowserEntrySaveDialog @@ -944,7 +1016,7 @@ Do you want to delete the entry? - KeePassXC - New key association request + Disable @@ -960,7 +1032,7 @@ Do you want to delete the entry? - Converting attributes to custom data… + KeePassXC - New key association request @@ -988,48 +1060,6 @@ Do you want to overwrite the passkey in %1 - %2? Register - - Abort - - - - KeePassXC: Converted KeePassHTTP attributes - - - - Successfully converted attributes from %1 entry(s). -Moved %2 keys to custom data. - - - - Successfully moved %n keys to custom data. - - - - - - - KeePassXC: No entry with KeePassHTTP attributes found! - - - - The active database does not contain an entry with KeePassHTTP attributes. - - - - Don't show this warning again - - - - KeePassXC: Legacy browser integration settings detected - - - - Your KeePassXC-Browser settings need to be moved into the database settings. -This is necessary to maintain your current browser connections. -Would you like to migrate your existing settings now? - - BrowserSettingsWidget @@ -1049,10 +1079,6 @@ Would you like to migrate your existing settings now? General - - Browsers installed as snaps are currently not supported. - - Enable integration for these browsers: @@ -1224,18 +1250,6 @@ Would you like to migrate your existing settings now? Custom extension ID - - Due to Snap sandboxing, you must run a script to enable browser integration.<br />You can obtain this script from %1 - - - - KeePassXC-Browser is needed for the browser integration to work. <br />Download it for %1 and %2 and %3. %4 - - - - Please see special instructions for browser extension use below - - Executable Files @@ -1252,6 +1266,14 @@ Would you like to migrate your existing settings now? Select native messaging host folder location + + Allow keepassxc-proxy to list all entries with their title, URL and UUID in connected databases. + + + + Allow limited access to all entries in connected databases (ignores site access restrictions) + + <b>Warning:</b> Only adjust these settings if necessary. @@ -1276,6 +1298,14 @@ Would you like to migrate your existing settings now? Allow using localhost with passkeys + + KeePassXC-Browser is needed for the browser integration to work. <br />Download it for %1 and %2 and %3. + + + + Browsers installed using Snap or Flatpak are not supported with exception to Firefox installed using Snap. + + CloneDialog @@ -1421,6 +1451,19 @@ Would you like to migrate your existing settings now? Imported from CSV file: %1 + + No Title Selected + + + + No title column was selected, entries will be hard to tell apart. +Are you sure you want to import? + + + + Tags + + CsvParserModel @@ -1489,6 +1532,14 @@ Backup database located at %2 Recycle Bin + + Database file read error. + + + + No file path was provided. + + DatabaseOpenDialog @@ -1580,10 +1631,6 @@ To prevent this error from appearing, you must go to "Database Settings / S Retry with empty password - - Failed to authenticate with Touch ID - - Failed to open key file: %1 @@ -1620,6 +1667,10 @@ To prevent this error from appearing, you must go to "Database Settings / S authenticate to access the database + + Failed to authenticate with Quick Unlock: %1 + + Select Key File: @@ -1628,14 +1679,6 @@ To prevent this error from appearing, you must go to "Database Settings / S <p>In addition to a password, you can use a secret file to enhance the security of your database. This file can be generated in your database's security settings.</p><p>This is <strong>not</strong> your *.kdbx database file!</p> - - Click to add a key file. - - - - <a href="#" style="text-decoration: underline">I have a key file</a> - - Use hardware key [Serial: %1] @@ -1669,11 +1712,19 @@ Are you sure you want to continue with this file?. - Windows Hello setup was canceled or failed. Quick unlock has not been enabled. + Click to add a key file. - Failed to authenticate with Windows Hello: %1 + <a href="#" style="text-decoration: underline">I have a key file</a> + + + + Hardware keys found, but no slots are configured. + + + + Press ESC again to close this database @@ -1710,6 +1761,22 @@ Are you sure you want to continue with this file?. Maintenance + + KeeShare + + + + Secret Service Integration + + + + Remote Sync + + + + Database Settings: %1 + + DatabaseSettingsWidgetBrowser @@ -1717,18 +1784,6 @@ Are you sure you want to continue with this file?. KeePassXC-Browser settings - - Convert KeePassHTTP data - - - - Convert legacy KeePassHTTP attributes to KeePassXC-Browser compatible custom data - - - - Refresh database root group ID - - Disconnect all browsers @@ -1737,6 +1792,10 @@ Are you sure you want to continue with this file?. Forget all site-specific settings on entries + + Refresh database root group ID + + Stored keys @@ -1818,15 +1877,6 @@ Permissions to access entries will be revoked. The active database does not contain an entry with permissions. - - Move KeePassHTTP attributes to custom data - - - - Do you really want to convert all legacy browser integration data to the latest standard? -This is necessary to maintain compatibility with the browser plugin. - - Refresh database ID @@ -1836,6 +1886,10 @@ This is necessary to maintain compatibility with the browser plugin. This is only necessary if your database is a copy of another and the browser extension cannot connect. + + Convert legacy KeePassHTTP attributes to KeePassXC-Browser compatible custom data + + No keys found @@ -1894,11 +1948,11 @@ Are you sure you want to continue without a password? - You must enter a stronger password to protect your database. + This is a weak password! For better protection of your secrets, you should choose a stronger password. - This is a weak password! For better protection of your secrets, you should choose a stronger password. + The provided password does not meet the minimum quality requirement. @@ -2194,6 +2248,50 @@ removed from the database. Autosave delay since last change checkbox + + Public Database Metadata + + + + Warning: the following settings are not encrypted. + + + + Display name: + + + + Publically visible display name used on the unlock dialog + + + + Database public display name + + + + Display color: + + + + Publically visible color used on the unlock dialog + + + + Database public display color chooser + + + + Clear + + + + Display icon: + + + + Select Database Icon + + DatabaseSettingsWidgetKeeShare @@ -2292,6 +2390,129 @@ removed from the database. + + DatabaseSettingsWidgetRemote + + Sync Commands + + + + Remove + + + + Command Settings + + + + Name + + + + Save + + + + Download + + + + Command: + + + + Download command field + + + + e.g.: "sftp user@hostname" or "scp user@hostname:DatabaseOnRemote.kdbx {TEMP_DATABASE}" + + + + Input: + + + + Download input field + + + + Upload + + + + Upload command field + + + + e.g.: "sftp user@hostname" or "scp {TEMP_DATABASE} user@hostname:DatabaseOnRemote.kdbx" + + + + Upload input field + + + + Name cannot be empty. + + + + Test + + + + Download command cannot be empty. + + + + Download failed with error: %1 + + + + Download finished, but file %1 could not be found. + + + + Download successful. + + + + Save Remote Settings + + + + You have unsaved changes. Do you want to save them? + + + + e.g.: +get DatabaseOnRemote.kdbx {TEMP_DATABASE} +exit +--- +{TEMP_DATABASE} is used as placeholder to store the database in a temporary location +The command has to exit. In case of `sftp` as last command `exit` has to be sent + + + + + e.g.: +put {TEMP_DATABASE} DatabaseOnRemote.kdbx +exit +--- +{TEMP_DATABASE} is used as placeholder to store the database in a temporary location +The command has to exit. In case of `sftp` as last command `exit` has to be sent + + + + + Timeout: + + + + seconds + + + DatabaseTabWidget @@ -2339,6 +2560,18 @@ This is definitely a bug, please report it to the developers. Writing the HTML file failed. + + Export database to XML file + + + + XML file + + + + Writing the XML file failed + + Export Confirmation @@ -2353,20 +2586,17 @@ This is definitely a bug, please report it to the developers. - Export database to XML file - - - - XML file - - - - Writing the XML file failed + %1 [Temporary] + Database tab name modifier DatabaseWidget + + Searches and Tags + + Searching… @@ -2415,6 +2645,13 @@ This is definitely a bug, please report it to the developers. Expired entries + + Entries expiring within %1 day(s) + + + + + No current database. @@ -2439,6 +2676,14 @@ This is definitely a bug, please report it to the developers. No Results + + Enter a unique name or overwrite an existing search from the list: + + + + Save Search + + Lock Database? @@ -2465,24 +2710,6 @@ Save changes? File has changed - - The database file has changed. Do you want to load the changes? - - - - Merge Request - - - - The database file has changed and you have unsaved changes. -Do you want to merge your changes? - - - - Could not open the new database file while attempting to autoreload. -Error: %1 - - Disable safe saves? @@ -2534,26 +2761,98 @@ Disable safe saves and try again? - Searches and Tags + Remote Sync did not contain any download or upload commands. - - Entries expiring within %1 day(s) - - - - + + Remote sync '%1' completed successfully! + + + + Remote sync '%1' failed: %2 + + + + Error while saving database %1: %2 + + + + Downloading... + + + + Uploading... + + + + Syncing... + + + + Remove passkey from entry + + + + Do you want to remove the passkey from this entry? + + + + The database file "%1" was modified externally + + + + Do you want to load the changes? + + + + Reload database + + + + Reloading database… + + + + Reload canceled + + + + Reload successful + + + + Reload pending user action… + + + + The database file "%1" was modified externally.<br>How would you like to proceed?<br><br>Merge all changes<br>Ignore the changes on disk until save<br>Discard unsaved changes + + + + The database file "%1" was modified externally.<br>How would you like to proceed?<br><br>Merge all changes then save<br>Overwrite the changes on disk<br>Discard unsaved changes + + + + Database file overwritten. + + + + Database file on disk cannot be unlocked with current credentials.<br>Enter new credentials and/or present hardware key to continue. + + + + Failed to save backup database: %1 + Save + + + EditEntryAttachmentsDialog - Enter a unique name or overwrite an existing search from the list: - - - - Save Search + Edit: %1 @@ -2607,10 +2906,6 @@ Disable safe saves and try again? n/a - - (encrypted) - - Select private key @@ -2692,6 +2987,13 @@ Would you like to correct it? Hide + + %n hour(s) + + + + + %n week(s) @@ -2713,12 +3015,9 @@ Would you like to correct it? - - %n hour(s) - - - - + + Failed to decrypt SSH key, ensure password is correct. + @@ -2838,10 +3137,20 @@ Would you like to correct it? Add new window association + + + + Add item + + Remove selected window association + + - + Remove item + + Window title: @@ -2866,16 +3175,6 @@ Would you like to correct it? Custom Auto-Type sequence for this window - - + - Add item - - - - - - Remove item - - EditEntryWidgetBrowser @@ -2891,18 +3190,10 @@ Would you like to correct it? Skip Auto-Submit for this entry - - Only send this setting to the browser for HTTP Auth dialogs. If enabled, normal login forms will not show this entry for selection. - - Use this entry only with HTTP Basic Auth - - Do not send this setting to the browser for HTTP Auth dialogs. If enabled, HTTP Auth dialogs will not show this entry for selection. - - Do not use this entry with HTTP Basic Auth @@ -2927,6 +3218,14 @@ Would you like to correct it? Additional URLs + + Only send this entry to the browser for HTTP Auth dialogs. If enabled, normal login forms will not show this entry for selection. + + + + Do not send this entry to the browser for HTTP Auth dialogs. If enabled, HTTP Auth dialogs will not show this entry for selection. + + EditEntryWidgetHistory @@ -3092,19 +3391,6 @@ Would you like to correct it? Private key - - External file - - - - Browser for key file - - - - Browse… - Button for opening file dialog - - Attachment @@ -3121,6 +3407,23 @@ Would you like to correct it? Remove from agent + + External file + + + + Browser for key file + + + + Browse… + Button for opening file dialog + + + + Generate + + Select attachment file @@ -3145,6 +3448,10 @@ Would you like to correct it? seconds + + Clear agent + + EditGroupWidget @@ -3156,10 +3463,6 @@ Would you like to correct it? Icon - - Browser Integration - - Properties @@ -3176,6 +3479,10 @@ Would you like to correct it? Group has unsaved changes + + Browser Integration + + Enable @@ -3235,6 +3542,14 @@ Would you like to correct it? Omit WWW subdomain from matching toggle for this and sub groups + + Restrict matching to given browser key: + + + + Restrict matching to given browser key toggle for this and sub groups + + EditGroupWidgetKeeShare @@ -3586,6 +3901,23 @@ This may cause the affected plugins to malfunction. %1 - Clone + + Passkey + + + + Invalid conversion type: %1 + + + + Invalid conversion syntax: %1 + + + + Invalid regular expression syntax %1 +%2 + + EntryAttachments @@ -3619,10 +3951,6 @@ This may cause the affected plugins to malfunction. Add new attachment - - Add - - Remove selected attachment @@ -3631,14 +3959,6 @@ This may cause the affected plugins to malfunction. Remove - - Rename selected attachment - - - - Rename - - Open selected attachment @@ -3651,10 +3971,6 @@ This may cause the affected plugins to malfunction. Save selected attachment to disk - - Save - - Select files @@ -3748,6 +4064,30 @@ Error: %1 Would you like to overwrite the existing attachment? + + Preview + + + + Edit + + + + New Text Document + + + + Add file… + + + + Load from Disk… + + + + Save… + + EntryAttributesModel @@ -3942,6 +4282,14 @@ Would you like to overwrite the existing attachment? Has TOTP + + Background Color + + + + Group Path + + EntryPreviewWidget @@ -3962,7 +4310,7 @@ Would you like to overwrite the existing attachment? - Notes + URL @@ -3982,7 +4330,7 @@ Would you like to overwrite the existing attachment? - URL + Notes @@ -4033,6 +4381,10 @@ Would you like to overwrite the existing attachment? Never + + Double click to copy value + + Enabled @@ -4041,10 +4393,6 @@ Would you like to overwrite the existing attachment? Disabled - - Double click to copy value - - Double click to copy to clipboard @@ -4303,6 +4651,13 @@ You can enable the DuckDuckGo website icon service in the security section of th + + ImageAttachmentsWidget + + Zoom: + + + ImportWizard @@ -4340,6 +4695,14 @@ You can enable the DuckDuckGo website icon service in the security section of th Url + + Could not load key file. + + + + Could not open remote database. Password or key file may be incorrect. + + ImportWizardPageSelect @@ -4443,6 +4806,44 @@ You can enable the DuckDuckGo website icon service in the security section of th KeePass1 Database + + Proton Pass (.json) + + + + Proton Pass JSON Export + + + + Temporary Database + + + + Command: + + + + e.g.: "sftp user@hostname" or "scp user@hostname:DatabaseOnRemote.kdbx {TEMP_DATABASE}" + + + + Input: + + + + e.g.: +get DatabaseOnRemote.kdbx {TEMP_DATABASE} +exit +--- +{TEMP_DATABASE} is used as placeholder to store the database in a temporary location +The command has to exit. In case of `sftp` as last commend `exit` has to be sent + + + + + Remote Database (.kdbx) + + KMessageWidget @@ -5244,6 +5645,10 @@ Are you sure you want to continue with this file? TOTP + + Tags + + &Groups @@ -5288,34 +5693,18 @@ Are you sure you want to continue with this file? &New Database… - - Create a new database - - &Merge From Database… - - Merge from another KDBX database - - &New Entry… - - Add a new entry - - &Edit Entry… - - View or edit entry - - &Delete Entry… @@ -5324,10 +5713,6 @@ Are you sure you want to continue with this file? &New Group… - - Add a new group - - &Edit Group… @@ -5360,18 +5745,10 @@ Are you sure you want to continue with this file? Database &Reports… - - Statistics, health check, etc. - - &Database Settings… - - Database settings - - &Clone Entry… @@ -5380,34 +5757,18 @@ Are you sure you want to continue with this file? Move u&p - - Move entry one step up - - Move do&wn - - Move entry one step down - - Copy &Username - - Copy username to clipboard - - Copy &Password - - Copy password to clipboard - - &Settings @@ -5441,21 +5802,13 @@ Are you sure you want to continue with this file? - Copy title to clipboard - - - - Copy URL to clipboard + Copy &URL &Notes - - Copy notes to clipboard - - &CSV File… @@ -5468,26 +5821,14 @@ Are you sure you want to continue with this file? KeePass 1 Database… - - Import a KeePass 1 database - - 1Password Vault… - - Import a 1Password Vault - - CSV File… - - Import a CSV file - - Show TOTP @@ -5504,6 +5845,10 @@ Are you sure you want to continue with this file? Copy &TOTP + + Copy Password and TOTP + + E&mpty recycle bin @@ -5528,10 +5873,6 @@ Are you sure you want to continue with this file? &Online Help - - Go to online documentation - - &User Guide @@ -5604,6 +5945,10 @@ Are you sure you want to continue with this file? Clone Group... + + &XML File… + + Clear history @@ -5628,8 +5973,7 @@ Expect some bugs and minor issues, this version is meant for testing purposes. - WARNING: Your Qt version may cause KeePassXC to crash with an On-Screen Keyboard. -We recommend you use the AppImage available on our downloads page. + No Tags @@ -5663,6 +6007,13 @@ We recommend you use the AppImage available on our downloads page. Quit KeePassXC + + %1 Entry(s) + + + + + Please present or touch your YubiKey to continue… @@ -5676,7 +6027,7 @@ We recommend you use the AppImage available on our downloads page. - Tags + Allow Screen Capture @@ -5695,49 +6046,294 @@ We recommend you use the AppImage available on our downloads page. Passkeys… - - %1 Entry(s) - - - - - - - Copy Password and TOTP - - - - &XML File… - - - - XML File… - - - - Copy &URL - - - - Allow Screen Capture - - - - Passkeys - - Import Passkey - No Tags + Remote S&ync… + + + + Quit Application + + + + Open About Dialog + + + + Open Database + + + + Create Database + + + + Merge From Database + + + + Create Entry + + + + Edit Entry + + + + Delete Entry + + + + Create Group + + + + Edit Group + + + + Delete Group + + + + Download All Favicons + + + + Sort Groups A-Z + + + + Sort Groups Z-A + + + + Save Database As + + + + Show Database Security + + + + Show Database Reports + + + + Show Database Settings + + + + Show Passkeys + + + + Clone Entry + + + + Move Entry Up + + + + Move Entry Down + + + + Copy Username + + + + Copy Password + + + + Show Application Settings + + + + Show Password Generator + + + + Remove Passkey From Entry + + + + Perform Auto-Type: {USERNAME} + + + + Perform Auto-Type: {USERNAME}{ENTER} + + + + Perform Auto-Type: {PASSWORD} + + + + Perform Auto-Type: {PASSWORD}{ENTER} + + + + Perform Auto-Type: {TOTP} + + + + Copy Title + + + + Copy URL + + + + Copy Notes + + + + Export to CSV + + + + Export to HTML + + + + Import KeePass1 Database + + + + Import 1Password Vault + + + + Import CSV File + + + + Show TOTP QR Code + + + + Set up TOTP + + + + Empty Recycle Bin + + + + Open Donation Website + + + + Open Bug Report + + + + Open Online Documentation + + + + Open Keyboard Shortcuts Guide + + + + Save Database Backup + + + + SSH Agent: Add Key + + + + SSH Agent: Remove Key + + + + Toggle Compact Mode + + + + Set Theme: Automatic + + + + Set Theme: Light + + + + Set Theme: Dark + + + + Set Theme: Classic Toggle Show Menubar + + Toggle Show Toolbar + + + + Toggle Show Preview Panel + + + + Toggle Always on Top + + + + Toggle Hide Usernames + + + + Toggle Hide Passwords + + + + Export to XML + + + + Toggle Allow Screen Capture + + + + Show Group Panel + + + + Toggle Show Group Panel + + + + Setup Remote Sync… + + + + Password Generator + + + + E&xpire Entry… + + + + Clear SSH Agent + + + + Clear all identities in ssh-agent + + ManageDatabase @@ -5795,26 +6391,6 @@ We recommend you use the AppImage available on our downloads page. Overwriting %1 [%2] - - older entry merged from database "%1" - - - - Adding backup for older target %1 [%2] - - - - Adding backup for older source %1 [%2] - - - - Reapplying older target entry on top of newer source %1 [%2] - - - - Reapplying older source entry on top of newer target %1 [%2] - - Synchronizing from newer source %1 [%2] @@ -6027,6 +6603,10 @@ We recommend you use the AppImage available on our downloads page. Unknown cipher: %1 + + AES-256/GCM is currently not supported + + Passphrase is required to decrypt this key @@ -6092,7 +6672,26 @@ We recommend you use the AppImage available on our downloads page. - AES-256/GCM is currently not supported + (encrypted) + + + + + OpenSSHKeyGenDialog + + SSH Key Generator + + + + Type + + + + Bits + + + + Comment @@ -6450,10 +7049,6 @@ The following data is missing: Word Count: - - Character Count: - - Word Case: @@ -6466,10 +7061,6 @@ The following data is missing: Add custom wordlist - - character - - Close @@ -6507,11 +7098,27 @@ The following data is missing: - Confirm Delete Wordlist + Password Quality: %1 - Do you really want to delete the wordlist "%1"? + Poor + Password quality + + + + Weak + Password quality + + + + Good + Password quality + + + + Excellent + Password quality @@ -6552,31 +7159,31 @@ Do you want to overwrite it? - Password Quality: %1 + passwordLength - Poor - Password quality + Characters: %1 - Weak - Password quality + MIXED case - Good - Password quality + Excluded characters: "0", "1", "l", "I", "O", "|", "﹒", "B", "8", "G", "6" - Excellent - Password quality + Warning: the chosen wordlist is smaller than the minimum recommended size! - Excluded characters: "0", "1", "l", "I", "O", "|", "﹒" + Confirm Remove Wordlist + + + + Do you really want to remove the wordlist "%1"? @@ -6627,7 +7234,7 @@ Do you want to overwrite it? - Toggle password visibilty using Control + H. Open the password generator using Control + G. + Toggle password visibility using Control + H. Open the password generator using Control + G. @@ -6646,6 +7253,21 @@ Do you want to overwrite it? + + PreviewEntryAttachmentsDialog + + Form + + + + Preview: %1 + + + + Save… + + + QMessageBox @@ -7087,6 +7709,10 @@ Do you want to overwrite it? Too many arguments provided. + + Path of the database. + + Target decryption time in MS for the database. @@ -7107,10 +7733,6 @@ Do you want to overwrite it? Create a new database. - - Path of the database. - - Invalid decryption time %1. @@ -7155,6 +7777,158 @@ Do you want to overwrite it? Successfully created new database. + + Unset the password for the database. + + + + Unset the key file for the database. + + + + Edit a database. + + + + Cannot use %1 and %2 at the same time. + + + + Could not change the database key. + + + + Database was not modified. + + + + Writing the database failed: %1 + + + + Successfully edited the database. + + + + Cannot remove password: The database does not have a password. + + + + Cannot remove file key: The database does not have a file key. + + + + Loading the new key file failed: %1 + + + + Found unexpected Key type %1 + + + + Cannot remove all the keys from a database. + + + + Show a database's information. + + + + UUID: + + + + Name: + + + + Description: + + + + Cipher: + + + + KDF: + + + + Recycle bin is enabled. + + + + Recycle bin is not enabled. + + + + Location + + + + Database created + + + + Last saved + + + + Unsaved changes + + + + yes + + + + no + + + + Number of groups + + + + Number of entries + + + + Number of expired entries + + + + Unique passwords + + + + Non-unique passwords + + + + Maximum password reuse + + + + Number of short passwords + + + + Number of weak passwords + + + + Entries excluded from reports + + + + Average password length + + + + %1 characters + + Word count for the diceware passphrase. @@ -7177,10 +7951,6 @@ Do you want to overwrite it? Invalid word count %1 - - The word list is too small (< 1000 items) - - Title for the entry. @@ -7205,10 +7975,6 @@ Do you want to overwrite it? Enter new password for entry: - - Writing the database failed: %1 - - Successfully edited entry %1. @@ -7329,10 +8095,6 @@ Do you want to overwrite it? Exit interactive mode. - - Format to use when exporting. Available choices are 'xml' or 'csv'. Defaults to 'xml'. - - Exports the content of a database to standard output in the specified format. @@ -7433,106 +8195,6 @@ Do you want to overwrite it? Successfully imported database. - - Show a database's information. - - - - UUID: - - - - Name: - - - - Description: - - - - Cipher: - - - - KDF: - - - - Recycle bin is enabled. - - - - Recycle bin is not enabled. - - - - Location - - - - Database created - - - - Last saved - - - - Unsaved changes - - - - yes - - - - no - - - - Number of groups - - - - Number of entries - - - - Number of expired entries - - - - Unique passwords - - - - Non-unique passwords - - - - Maximum password reuse - - - - Number of short passwords - - - - Number of weak passwords - - - - Entries excluded from reports - - - - Average password length - - - - %1 characters - - Unknown command %1 @@ -7701,6 +8363,10 @@ Available commands: Show the protected attributes in clear text. + + Show all the attributes of the entry. + + Show the attachments of the entry. @@ -7768,6 +8434,10 @@ Please consider generating a new key file. Invalid YubiKey serial %1 + + Please present or touch your YubiKey to continue. + + Enter password to encrypt database (optional): @@ -8027,18 +8697,6 @@ Kernel: %3 %4 file empty - - malformed string - - - - missing closing quote - - - - %1: (row, col) %2,%3 - - AES 256-bit @@ -8249,6 +8907,10 @@ Kernel: %3 %4 Another instance of KeePassXC is already running. + + KeePassXC is not running. No open database to lock + + Fatal error while testing the cryptographic functions. @@ -8292,11 +8954,11 @@ Kernel: %3 %4 - Please present or touch your YubiKey to continue. + Access to all entries is denied - Show all the attributes of the entry. + allow screenshots and app recording (Windows/macOS) @@ -8313,23 +8975,23 @@ This option is deprecated, use --set-key-file instead. - Loading the new key file failed: %1 + Credential is excluded - Unset the password for the database. + Passkeys request canceled - Unset the key file for the database. + Invalid user verification - Cannot use %1 and %2 at the same time. + Empty public key - Cannot remove all the keys from a database. + Invalid URL provided @@ -8337,15 +8999,59 @@ This option is deprecated, use --set-key-file instead. - Found unexpected Key type %1 + AES initialization failed - KeePassXC is not running. No open database to lock + AES encrypt failed - allow screenshots and app recording (Windows/macOS) + Failed to store in Linux Keyring + + + + Polkit returned an error: %1 + + + + Could not locate key in keyring + + + + Could not read key in keyring + + + + AES decrypt failed + + + + No Polkit authentication agent was available + + + + Polkit authorization failed + + + + No Quick Unlock provider is available + + + + Failed to init KeePassXC crypto. + + + + Failed to encrypt key data. + + + + Failed to get Windows Hello credential. + + + + Failed to decrypt key data. @@ -8376,10 +9082,6 @@ This option is deprecated, use --set-key-file instead. user.id does not match the required length - - Access to all entries is denied - - Favorite Tag for favorite entries @@ -8451,57 +9153,118 @@ This option is deprecated, use --set-key-file instead. - Credential is excluded + Enter Shortcut - Passkeys request canceled + Action - Invalid user verification - - - - Empty public key - - - - Invalid URL provided - - - - Edit a database. - - - - Could not change the database key. - - - - Database was not modified. - - - - Successfully edited the database. - - - - Cannot remove password: The database does not have a password. - - - - Cannot remove file key: The database does not have a file key. - - - - Unsupported KDF type, cannot decrypt json file + Shortcuts Unknown passkeys error + + Invalid KDF iterations, cannot decrypt json file + + + + Unsupported format, ensure your Bitwarden export is password-protected + + + + Only PBKDF and Argon2 are supported, cannot decrypt json file + + + + Reset Shortcuts + + + + Double click an action to change its shortcut + + + + Filter... + + + + Shortcut Conflict + + + + Shortcut %1 conflicts with '%2'. Overwrite shortcut? + + + + Encrypted files are not supported. + + + + Proton Pass Import + + + + Delete plugin data? + + + + Delete plugin data from Entry(s)? + + + + + + + Passkey + + + + Format to use when exporting. Available choices are 'xml', 'csv' or 'html'. Defaults to 'xml'. + + + + start minimized to the system tray + + + + malformed string, possible unescaped delimiter + + + + missing closing delimiter + + + + %1, row: %2, column: %3 + + + + Tags + + + + Warning: the chosen wordlist is smaller than the minimum recommended size! + + + + Invalid Step + TOTP + + + + Invalid Digits + TOTP + + + + Fit + + QtIOCompressor @@ -8537,6 +9300,37 @@ This option is deprecated, use --set-key-file instead. + + RemoteHandler + + Command `%1` did not finish in time. Process was killed. + + + + Failed to upload merged database. Command `%1` did not finish in time. Process was killed. + + + + Invalid download parameters provided. + + + + Command `%1` failed to download database. + + + + Invalid database pointer or upload parameters provided. + + + + Command `%1` exited with status code: %2 + + + + Failed to upload merged database. Command `%1` exited with status code: %2 + + + ReportsWidgetBrowserStatistics @@ -8606,6 +9400,13 @@ This option is deprecated, use --set-key-file instead. Exclude from reports + + Expire Entry(s)… + + + + + Only show entries that have a URL @@ -8622,36 +9423,36 @@ This option is deprecated, use --set-key-file instead. (Expired) + + Delete plugin data from Entry(s)… + + + + + ReportsWidgetHealthcheck - Hover over reason to show additional details. Double-click entries to edit. + Show expired entries - Bad - Password quality + (Expired) + + + + Hover over reason to show additional details. Double-click entries to edit. Bad — password must be changed - - Poor - Password quality - - Poor — password should be changed - - Weak - Password quality - - Weak — consider changing the password @@ -8703,18 +9504,17 @@ This option is deprecated, use --set-key-file instead. Exclude from reports - - Show expired entries - + + Expire Entry(s)… + + + + Show entries that have been excluded from reports - - (Expired) - - ReportsWidgetHibp @@ -8813,6 +9613,13 @@ This option is deprecated, use --set-key-file instead. Exclude from reports + + Expire Entry(s)… + + + + + ReportsWidgetPasskeys @@ -9057,6 +9864,14 @@ This option is deprecated, use --set-key-file instead. No agent running, cannot list identities. + + Failed to remove all SSH identities from agent. + + + + All SSH identities removed from agent. + + SearchHelpWidget @@ -9123,6 +9938,10 @@ This option is deprecated, use --set-key-file instead. Search Help + + Save Search + + Search (%1)… Search placeholder text, %1 is the keyboard shortcut @@ -9137,7 +9956,7 @@ This option is deprecated, use --set-key-file instead. - Save Search + Press Enter to search @@ -9344,6 +10163,14 @@ This option is deprecated, use --set-key-file instead. TagModel + + Clear Search + + + + All Entries + + Expired @@ -9353,11 +10180,7 @@ This option is deprecated, use --set-key-file instead. - All Entries - - - - Clear Search + TOTP Entries @@ -9380,6 +10203,24 @@ This option is deprecated, use --set-key-file instead. + + TextAttachmentsEditWidget + + Preview + + + + + TextAttachmentsPreviewWidget + + Form + + + + Type: + + + TotpDialog @@ -9494,6 +10335,10 @@ Example: JBSWY3DPEHPK3PXP Are you sure you want to delete TOTP settings for this entry? + + Error: secret key is invalid + + URLEdit @@ -9579,25 +10424,6 @@ Example: JBSWY3DPEHPK3PXP - - WindowsHello - - Failed to init KeePassXC crypto. - - - - Failed to encrypt key data. - - - - Failed to get Windows Hello credential. - - - - Failed to decrypt key data. - - - YubiKey @@ -9643,10 +10469,6 @@ Example: JBSWY3DPEHPK3PXP Challenge-Response set, click to change or remove - - <p>If you own a <a href="https://www.yubico.com/">YubiKey</a> or <a href="https://onlykey.io">OnlyKey</a>, you can use it for additional security.</p><p>The key requires one of its slots to be programmed as <a href="https://www.yubico.com/products/services-software/challenge-response/">HMAC-SHA1 Challenge-Response</a>.</p> - - Detecting hardware keys… @@ -9659,6 +10481,14 @@ Example: JBSWY3DPEHPK3PXP Refresh hardware keys + + <p>If you own a <a href="https://www.yubico.com/">YubiKey</a> or <a href="https://onlykey.io">OnlyKey</a>, you can use it for additional security.</p><p>The key requires one of its slots to be programmed with <a href="https://keepassxc.org/docs/#faq-yubikey-howto">Challenge-Response</a>.</p> + + + + Hardware keys found, but no slots are configured + + YubiKeyInterfacePCSC diff --git a/share/translations/keepassxc_en_GB.ts b/share/translations/keepassxc_en_GB.ts index ae32da1f7..1bc6cbad6 100644 --- a/share/translations/keepassxc_en_GB.ts +++ b/share/translations/keepassxc_en_GB.ts @@ -217,18 +217,50 @@ You must restart the application to set the new language. Would you like to restart now? You must restart the application to set the new language. Would you like to restart now? - - Reset Settings? - Reset Settings? - - - Are you sure you want to reset all general and security settings to default? - Are you sure you want to reset all general and security settings to default? - Select backup storage directory Select backup storage directory + + Confirm Reset + Confirm Reset + + + Are you sure you want to reset all settings to default? + Are you sure you want to reset all settings to default? + + + Import KeePassXC Settings + Import KeePassXC Settings + + + Failed to import settings from %1, not a valid settings file. + Failed to import settings from %1, not a valid settings file. + + + Export KeePassXC Settings + Export KeePassXC Settings + + + Small + Small + + + Normal + Normal + + + Medium + Medium + + + Large + Large + + + Custom + Custom + ApplicationSettingsWidgetGeneral @@ -280,25 +312,6 @@ Include beta releases when checking for updates Include beta releases when checking for updates - - On database unlock, show entries that - On database unlock, show entries that - - - have expired - On database unlock, show entries that... - have expired - - - days - On database unlock, show entries that will expire within %1 days - days - - - will expire within - On database unlock, show entries that... - will expire within - File Management File Management @@ -323,22 +336,10 @@ Backup database file before saving Backup database file before saving - - Backup destination - Backup destination - - - Specifies the database backup file location. Occurrences of "{DB_FILENAME}" are replaced with the filename of the saved database without extension. {TIME:<format>} is replaced with the backup time, see https://doc.qt.io/qt-5/qdatetime.html#toString. <format> defaults to format string "dd_MM_yyyy_hh-mm-ss". - Specifies the database backup file location. Occurrences of "{DB_FILENAME}" are replaced with the filename of the saved database without extension. {TIME:<format>} is replaced with the backup time, see https://doc.qt.io/qt-5/qdatetime.html#toString. <format> defaults to format string "dd_MM_yyyy_hh-mm-ss". - {DB_FILENAME}.old.kdbx {DB_FILENAME}.old.kdbx - - Choose... - Choose... - Use alternative saving method (may solve problems with Dropbox, Google Drive, GVFS, etc.) Use alternative saving method (may solve problems with Dropbox, Google Drive, GVFS, etc.) @@ -505,6 +506,71 @@ Remember last typed entry for: Remember last typed entry for: + + On database unlock, show entries that will expire within + On database unlock, show entries that will expire within + + + On database unlock, show entries that will expire within + On database unlock, show entries that will expire within + + + days + number of days warning for password expiration + days + + + Destination format: + Destination format: + + + <html><head/><body><p><span style=" font-weight:600;">{DB_FILENAME}</span> is replaced with the filename of the saved database without extension</p><p><span style=" font-weight:600;">{TIME:&lt;format&gt;}</span> is replaced with the specified time format (default: dd_MM_yyyy_hh-mm-ss)</p><p>See the User Guide for more details</p></body></html> + <html><head/><body><p><span style=" font-weight:600;">{DB_FILENAME}</span> is replaced with the filename of the saved database without extension</p><p><span style=" font-weight:600;">{TIME:&lt;format&gt;}</span> is replaced with the specified time format (default: dd_MM_yyyy_hh-mm-ss)</p><p>See the User Guide for more details</p></body></html> + + + Choose folder... + Choose folder... + + + Show confirmation before moving entries to recycle bin + Show confirmation before moving entries to recycle bin + + + Copy data on double clicking field in entry view + Copy data on double clicking field in entry view + + + Show toolbar + Show toolbar + + + Show the menu bar by pressing the Alt key + Show the menu bar by pressing the Alt key + + + Show menubar + Show menubar + + + Import settings… + Import settings… + + + Export settings… + Export settings… + + + Open browser on double clicking URL field in entry view + Open browser on double clicking URL field in entry view + + + Font size: + Font size: + + + Font size selection + Font size selection + ApplicationSettingsWidgetSecurity @@ -570,18 +636,6 @@ Hide passwords in the entry preview panel Hide passwords in the entry preview panel - - Hide entry notes by default - Hide entry notes by default - - - Move entries to recycle bin without confirmation - Move entries to recycle bin without confirmation - - - Enable double click to copy the username/password entry columns - Enable double-click to copy the username/password entry columns - Privacy Privacy @@ -594,6 +648,18 @@ Hide TOTP in the entry preview panel Hide TOTP in the entry preview panel + + Lock databases when switching user + Lock databases when switching user + + + Lock Options + Lock Options + + + Hide notes in the entry preview panel + Hide notes in the entry preview panel + AutoType @@ -641,20 +707,6 @@ Entry does not have attribute for PICKCHARS: %1 Entry does not have attribute for PICKCHARS: %1 - - Invalid conversion type: %1 - Invalid conversion type: %1 - - - Invalid conversion syntax: %1 - Invalid conversion syntax: %1 - - - Invalid regular expression syntax %1 -%2 - Invalid regular expression syntax %1 -%2 - Invalid placeholder: %1 Invalid placeholder: %1 @@ -714,7 +766,7 @@ Trying to send invalid keyboard symbol. - + Trying to send invalid keyboard symbol. @@ -886,24 +938,25 @@ Please select the correct database for saving credentials. Add to existing entry - + Add to existing entry Existing passkey found. Do you want to register a new passkey for: - + Existing passkey found. +Do you want to register a new passkey for: Select the existing passkey and press Update to replace it. - + Select the existing passkey and press Update to replace it. Authenticate passkey credentials for: - + Authenticate passkey credentials for: Do you want to register a passkey for: - + Do you want to register a passkey for: @@ -988,16 +1041,17 @@ Do you want to delete the entry? Register a new passkey to this entry: - + Register a new passkey to this entry: KeePassXC - Update passkey - + KeePassXC - Update passkey Entry already has a passkey. Do you want to overwrite the passkey in %1 - %2? - + Entry already has a passkey. +Do you want to overwrite the passkey in %1 - %2? Register @@ -1022,10 +1076,6 @@ Do you want to overwrite the passkey in %1 - %2? General General - - Browsers installed as snaps are currently not supported. - Browsers installed as snaps are currently not supported. - Enable integration for these browsers: Enable integration for these browsers: @@ -1197,18 +1247,6 @@ Do you want to overwrite the passkey in %1 - %2? Custom extension ID Custom extension ID - - Due to Snap sandboxing, you must run a script to enable browser integration.<br />You can obtain this script from %1 - Due to Snap sandboxing, you must run a script to enable browser integration.<br />You can obtain this script from %1 - - - KeePassXC-Browser is needed for the browser integration to work. <br />Download it for %1 and %2 and %3. %4 - KeePassXC-Browser is needed for the browser integration to work. <br />Download it for %1 and %2 and %3. %4 - - - Please see special instructions for browser extension use below - Please see special instructions for browser extension use below - Executable Files Executable Files @@ -1251,10 +1289,18 @@ Do you want to overwrite the passkey in %1 - %2? Allows using insecure http://localhost with passkeys for testing purposes. - + Allows using insecure http://localhost with passkeys for testing purposes. Allow using localhost with passkeys + Allow using localhost with passkeys + + + KeePassXC-Browser is needed for the browser integration to work. <br />Download it for %1 and %2 and %3. + KeePassXC-Browser is needed for the browser integration to work. <br />Download it for %1 and %2 and %3. + + + Browsers installed using Snap or Flatpak are not supported with exception to Firefox installed using Snap. @@ -1399,6 +1445,20 @@ Do you want to overwrite the passkey in %1 - %2? Imported from CSV file: %1 Imported from CSV file: %1 + + No Title Selected + No Title Selected + + + No title column was selected, entries will be hard to tell apart. +Are you sure you want to import? + No title column was selected, entries will be hard to tell apart. +Are you sure you want to import? + + + Tags + Tags + CsvParserModel @@ -1462,6 +1522,14 @@ Backup database located at %2 Recycle Bin Recycle Bin + + Database file read error. + Database file read error. + + + No file path was provided. + + DatabaseOpenDialog @@ -1610,14 +1678,6 @@ To prevent this error from appearing, you must go to "Database Settings / S <p>In addition to a password, you can use a secret file to enhance the security of your database. This file can be generated in your database's security settings.</p><p>This is <strong>not</strong> your *.kdbx database file!</p> <p>In addition to a password, you can use a secret file to enhance the security of your database. This file can be generated in your database's security settings.</p><p>This is <strong>not</strong> your *.kdbx database file!</p> - - Click to add a key file. - Click to add a key file. - - - <a href="#" style="text-decoration: underline">I have a key file</a> - <a href="#" style="text-decoration: underline">I have a key file</a> - Use hardware key [Serial: %1] Use hardware key [Serial: %1] @@ -1654,6 +1714,18 @@ Are you sure you want to continue with this file?. Refresh Hardware Keys Refresh Hardware Keys + + Click to add a key file. + Click to add a key file. + + + <a href="#" style="text-decoration: underline">I have a key file</a> + <a href="#" style="text-decoration: underline">I have a key file</a> + + + Hardware keys found, but no slots are configured. + Hardware keys found, but no slots are configured. + DatabaseSettingWidgetMetaData @@ -1688,6 +1760,22 @@ Are you sure you want to continue with this file?. Maintenance Maintenance + + KeeShare + KeeShare + + + Secret Service Integration + Secret Service Integration + + + Remote Sync + Remote Sync + + + Database Settings: %1 + Database Settings: %1 + DatabaseSettingsWidgetBrowser @@ -1858,14 +1946,14 @@ Are you sure you want to continue without a password? Weak password Weak password - - You must enter a stronger password to protect your database. - You must enter a stronger password to protect your database. - This is a weak password! For better protection of your secrets, you should choose a stronger password. This is a weak password! For better protection of your secrets, you should choose a stronger password. + + The provided password does not meet the minimum quality requirement. + The provided password does not meet the minimum quality requirement. + DatabaseSettingsWidgetEncryption @@ -2167,6 +2255,50 @@ removed from the database. Autosave delay since last change checkbox Autosave delay since last change checkbox + + Public Database Metadata + Public Database Metadata + + + Warning: the following settings are not encrypted. + Warning: the following settings are not encrypted. + + + Display name: + Display name: + + + Publically visible display name used on the unlock dialog + Publically visible display name used on the unlock dialogue + + + Database public display name + Database public display name + + + Display color: + Display colour: + + + Publically visible color used on the unlock dialog + Publically visible colour used on the unlock dialogue + + + Database public display color chooser + Database public display colour chooser + + + Clear + Clear + + + Display icon: + Display icon: + + + Select Database Icon + Select Database Icon + DatabaseSettingsWidgetKeeShare @@ -2262,6 +2394,141 @@ removed from the database. Database description field + + DatabaseSettingsWidgetRemote + + Sync Commands + Sync Commands + + + Remove + Remove + + + Command Settings + Command Settings + + + Name + Name + + + Save + Save + + + Download + Download + + + Command: + Command: + + + Download command field + Download command field + + + e.g.: "sftp user@hostname" or "scp user@hostname:DatabaseOnRemote.kdbx {TEMP_DATABASE}" + e.g.: "sftp user@hostname" or "scp user@hostname:DatabaseOnRemote.kdbx {TEMP_DATABASE}" + + + Input: + Input: + + + Download input field + Download input field + + + Upload + Upload + + + Upload command field + Upload command field + + + e.g.: "sftp user@hostname" or "scp {TEMP_DATABASE} user@hostname:DatabaseOnRemote.kdbx" + e.g.: "sftp user@hostname" or "scp {TEMP_DATABASE} user@hostname:DatabaseOnRemote.kdbx" + + + Upload input field + Upload input field + + + Name cannot be empty. + Name cannot be empty. + + + Test + Test + + + Download command cannot be empty. + Download command cannot be empty. + + + Download failed with error: %1 + Download failed with error: %1 + + + Download finished, but file %1 could not be found. + Download finished, but file %1 could not be found. + + + Download successful. + Download successful. + + + Save Remote Settings + Save Remote Settings + + + You have unsaved changes. Do you want to save them? + You have unsaved changes. Do you want to save them? + + + e.g.: +get DatabaseOnRemote.kdbx {TEMP_DATABASE} +exit +--- +{TEMP_DATABASE} is used as placeholder to store the database in a temporary location +The command has to exit. In case of `sftp` as last command `exit` has to be sent + + e.g.: +get DatabaseOnRemote.kdbx {TEMP_DATABASE} +exit +--- +{TEMP_DATABASE} is used as placeholder to store the database in a temporary location +The command has to exit. In case of `sftp` as last command `exit` has to be sent + + + + e.g.: +put {TEMP_DATABASE} DatabaseOnRemote.kdbx +exit +--- +{TEMP_DATABASE} is used as placeholder to store the database in a temporary location +The command has to exit. In case of `sftp` as last command `exit` has to be sent + + e.g.: +put {TEMP_DATABASE} DatabaseOnRemote.kdbx +exit +--- +{TEMP_DATABASE} is used as placeholder to store the database in a temporary location +The command has to exit. In case of `sftp` as last command `exit` has to be sent + + + + Timeout: + Timeout: + + + seconds + seconds + + DatabaseTabWidget @@ -2335,6 +2602,11 @@ This is definitely a bug, please report it to the developers. Database tab name modifier %1 [Locked] + + %1 [Temporary] + Database tab name modifier + %1 [Temporary] + DatabaseWidget @@ -2458,26 +2730,6 @@ Save changes? File has changed File has changed - - The database file has changed. Do you want to load the changes? - The database file has changed. Do you want to load the changes? - - - Merge Request - Merge Request - - - The database file has changed and you have unsaved changes. -Do you want to merge your changes? - The database file has changed and you have unsaved changes. -Do you want to merge your changes? - - - Could not open the new database file while attempting to autoreload. -Error: %1 - Could not open the new database file while attempting to autoreload. -Error: %1 - Disable safe saves? Disable safe saves? @@ -2529,6 +2781,86 @@ Disable safe saves and try again? Database tab name modifier %1 [New Database] + + Remote Sync did not contain any download or upload commands. + Remote Sync did not contain any download or upload commands. + + + Remote sync '%1' completed successfully! + Remote sync '%1' completed successfully! + + + Remote sync '%1' failed: %2 + Remote sync '%1' failed: %2 + + + Error while saving database %1: %2 + Error while saving database %1: %2 + + + Downloading... + Downloading... + + + Uploading... + Uploading... + + + Syncing... + Syncing... + + + Remove passkey from entry + Remove passkey from entry + + + Do you want to remove the passkey from this entry? + Do you want to remove the passkey from this entry? + + + The database file "%1" was modified externally + The database file "%1" was modified externally + + + Do you want to load the changes? + Do you want to load the changes? + + + Reload database + Reload database + + + Reloading database… + Reloading database… + + + Reload canceled + Reload cancelled + + + Reload successful + Reload successful + + + Reload pending user action… + Reload pending user action… + + + The database file "%1" was modified externally.<br>How would you like to proceed?<br><br>Merge all changes<br>Ignore the changes on disk until save<br>Discard unsaved changes + The database file "%1" was modified externally.<br>How would you like to proceed?<br><br>Merge all changes<br>Ignore the changes on disk until save<br>Discard unsaved changes + + + The database file "%1" was modified externally.<br>How would you like to proceed?<br><br>Merge all changes then save<br>Overwrite the changes on disk<br>Discard unsaved changes + The database file "%1" was modified externally.<br>How would you like to proceed?<br><br>Merge all changes then save<br>Overwrite the changes on disk<br>Discard unsaved changes + + + Database file overwritten. + Database file overwritten. + + + Database file on disk cannot be unlocked with current credentials.<br>Enter new credentials and/or present hardware key to continue. + Database file on disk cannot be unlocked with current credentials.<br>Enter new credentials and/or present hardware key to continue. + EditEntryWidget @@ -2580,10 +2912,6 @@ Disable safe saves and try again? n/a n/a - - (encrypted) - (encrypted) - Select private key Select private key @@ -2686,6 +3014,10 @@ Would you like to correct it? %n year(s) %n year%n years + + Failed to decrypt SSH key, ensure password is correct. + Failed to decrypt SSH key, ensure password is correct. + EditEntryWidgetAdvanced @@ -2857,18 +3189,10 @@ Would you like to correct it? Skip Auto-Submit for this entry Skip Auto-Submit for this entry - - Only send this setting to the browser for HTTP Auth dialogs. If enabled, normal login forms will not show this entry for selection. - Only send this setting to the browser for HTTP Auth dialogues. If enabled, normal login forms will not show this entry for selection. - Use this entry only with HTTP Basic Auth Use this entry only with HTTP Basic Auth - - Do not send this setting to the browser for HTTP Auth dialogs. If enabled, HTTP Auth dialogs will not show this entry for selection. - Do not send this setting to the browser for HTTP Auth dialogues. If enabled, HTTP Auth dialogues will not show this entry for selection. - Do not use this entry with HTTP Basic Auth Do not use this entry with HTTP Basic Auth @@ -2887,11 +3211,19 @@ Would you like to correct it? These settings affect the entry's behaviour with the browser extension. - + These settings affect the entry's behaviour with the browser extension. Additional URLs - + Additional URLs + + + Only send this entry to the browser for HTTP Auth dialogs. If enabled, normal login forms will not show this entry for selection. + Only send this entry to the browser for HTTP Auth dialogues. If enabled, normal login forms will not show this entry for selection. + + + Do not send this entry to the browser for HTTP Auth dialogs. If enabled, HTTP Auth dialogs will not show this entry for selection. + Do not send this entry to the browser for HTTP Auth dialogues. If enabled, HTTP Auth dialogues will not show this entry for selection. @@ -3115,6 +3447,10 @@ Would you like to correct it? seconds seconds + + Clear agent + Clear agent + EditGroupWidget @@ -3557,6 +3893,24 @@ This may cause the affected plugins to malfunction. %1 - Clone %1 - Clone + + Passkey + Passkey + + + Invalid conversion type: %1 + Invalid conversion type: %1 + + + Invalid conversion syntax: %1 + Invalid conversion syntax: %1 + + + Invalid regular expression syntax %1 +%2 + Invalid regular expression syntax %1 +%2 + EntryAttachments @@ -3565,6 +3919,21 @@ This may cause the affected plugins to malfunction. Cannot open file "%1" + + EntryAttachmentsDialog + + Form + Form + + + File name + File name + + + File contents... + File contents... + + EntryAttachmentsModel @@ -3602,14 +3971,6 @@ This may cause the affected plugins to malfunction. Remove Remove - - Rename selected attachment - Rename selected attachment - - - Rename - Rename - Open selected attachment Open selected attachment @@ -3725,6 +4086,18 @@ Would you like to overwrite the existing attachment? Attachment "%1" already exists. Would you like to overwrite the existing attachment? + + New + New + + + Preview + Preview + + + Failed to preview an attachment: Attachment not found + Failed to preview an attachment: Attachment not found + EntryAttributesModel @@ -3923,6 +4296,10 @@ Would you like to overwrite the existing attachment? Background Color Background Colour + + Group Path + Group Path + EntryPreviewWidget @@ -4318,6 +4695,14 @@ You can enable the DuckDuckGo website icon service in the security section of th Url URL + + Could not load key file. + Could not load key file. + + + Could not open remote database. Password or key file may be incorrect. + Could not open remote database. Password or key file may be incorrect. + ImportWizardPageSelect @@ -4421,6 +4806,50 @@ You can enable the DuckDuckGo website icon service in the security section of th KeePass1 Database KeePass1 Database + + Proton Pass (.json) + Proton Pass (.json) + + + Proton Pass JSON Export + Proton Pass JSON Export + + + Temporary Database + Temporary Database + + + Command: + Command: + + + e.g.: "sftp user@hostname" or "scp user@hostname:DatabaseOnRemote.kdbx {TEMP_DATABASE}" + e.g.: "sftp user@hostname" or "scp user@hostname:DatabaseOnRemote.kdbx {TEMP_DATABASE}" + + + Input: + Input: + + + e.g.: +get DatabaseOnRemote.kdbx {TEMP_DATABASE} +exit +--- +{TEMP_DATABASE} is used as placeholder to store the database in a temporary location +The command has to exit. In case of `sftp` as last commend `exit` has to be sent + + e.g.: +get DatabaseOnRemote.kdbx {TEMP_DATABASE} +exit +--- +{TEMP_DATABASE} is used as placeholder to store the database in a temporary location +The command has to exit. In case of `sftp` as last commend `exit` has to be sent + + + + Remote Database (.kdbx) + Remote Database (.kdbx) + KMessageWidget @@ -5506,7 +5935,7 @@ Are you sure you want to continue with this file? Show Menubar - + Show Menubar Show Toolbar @@ -5561,12 +5990,6 @@ This version is not meant for production use. Expect some bugs and minor issues, this version is meant for testing purposes. NOTE: You are using a pre-release version of KeePassXC. Expect some bugs and minor issues; this version is meant for testing purposes. - - - WARNING: Your Qt version may cause KeePassXC to crash with an On-Screen Keyboard. -We recommend you use the AppImage available on our downloads page. - WARNING: Your Qt version may cause KeePassXC to crash with an On-Screen Keyboard. -We recommend you use the AppImage available on our downloads page. No Tags @@ -5640,6 +6063,10 @@ We recommend you use the AppImage available on our downloads page. Import Passkey Import Passkey + + Remote S&ync… + Remote S&ync… + Quit Application Quit Application @@ -5744,6 +6171,10 @@ We recommend you use the AppImage available on our downloads page. Show Password Generator Show Password Generator + + Remove Passkey From Entry + Remove Passkey From Entry + Perform Auto-Type: {USERNAME} Perform Auto-Type: {USERNAME} @@ -5858,7 +6289,7 @@ We recommend you use the AppImage available on our downloads page. Toggle Show Menubar - + Toggle Show Menubar Toggle Show Toolbar @@ -5888,6 +6319,34 @@ We recommend you use the AppImage available on our downloads page. Toggle Allow Screen Capture Toggle Allow Screen Capture + + Show Group Panel + Show Group Panel + + + Toggle Show Group Panel + Toggle Show Group Panel + + + Setup Remote Sync… + Setup Remote Sync… + + + Password Generator + Password Generator + + + E&xpire Entry… + E&xpire Entry… + + + Clear SSH Agent + Clear SSH Agent + + + Clear all identities in ssh-agent + Clear all identities in ssh-agent + ManageDatabase @@ -6038,6 +6497,25 @@ We recommend you use the AppImage available on our downloads page. Please fill in the display name and an optional description for your new database: + + NewEntryAttachmentsDialog + + Attachment name cannot be empty + Attachment name cannot be empty + + + Attachment with the same name already exists + Attachment with the same name already exists + + + Save attachment + Save attachment + + + New entry attachment + New entry attachment + + NixUtils @@ -6225,6 +6703,10 @@ We recommend you use the AppImage available on our downloads page. Unexpected EOF when writing private key Unexpected EOF when writing private key + + (encrypted) + (encrypted) + OpenSSHKeyGenDialog @@ -6273,7 +6755,7 @@ We recommend you use the AppImage available on our downloads page. Export the following passkey entries. - + Export the following passkey entries. @@ -6347,15 +6829,15 @@ Do you want to overwrite it? Import the following passkey: - + Import the following passkey: Import the following passkey to this entry: - + Import the following passkey to this entry: Default passkeys group (Imported Passkeys) - + Default passkeys group (Imported Passkeys) @@ -6378,25 +6860,27 @@ Do you want to overwrite it? Open passkey file - + Open passkey file Cannot import passkey - + Cannot import passkey Cannot import passkey file "%1". Data is missing. - + Cannot import passkey file "%1". Data is missing. Cannot import passkey file "%1". The following data is missing: %2 - + Cannot import passkey file "%1". +The following data is missing: +%2 Cannot import passkey file "%1". Private key is missing or malformed. - + Cannot import passkey file "%1". Private key is missing or malformed. @@ -6577,10 +7061,6 @@ The following data is missing: Also choose from: Also choose from: - - Excluded characters: "0", "1", "l", "I", "O", "|", "﹒" - Excluded characters: "0", "1", "l", "I", "O", "|", "﹒" - Exclude look-alike characters Exclude look-alike characters @@ -6605,10 +7085,6 @@ The following data is missing: Word Count: Word Count: - - Character Count: - Character Count: - Word Case: Word Case: @@ -6621,10 +7097,6 @@ The following data is missing: Add custom wordlist Add custom wordlist - - character - character - Close Close @@ -6731,6 +7203,22 @@ Do you want to overwrite it? Special Characters Special Characters + + passwordLength + passwordLength + + + Characters: %1 + Characters: %1 + + + MIXED case + MIXED case + + + Excluded characters: "0", "1", "l", "I", "O", "|", "﹒", "B", "8", "G", "6" + Excluded characters: "0", "1", "l", "I", "O", "|", "﹒", "B", "8", "G", "6" + PasswordWidget @@ -6798,6 +7286,21 @@ Do you want to overwrite it? Press &Tab between characters + + PreviewEntryAttachmentsDialog + + Preview entry attachment + Preview entry attachment + + + No preview available + No preview available + + + Image format not supported + Image format not supported + + QMessageBox @@ -7476,10 +7979,6 @@ Do you want to overwrite it? Invalid word count %1 Invalid word count %1 - - The word list is too small (< 1000 items) - The word list is too small (< 1000 items) - Title for the entry. Title for the entry. @@ -7624,10 +8123,6 @@ Do you want to overwrite it? Exit interactive mode. Exit interactive mode. - - Format to use when exporting. Available choices are 'xml' or 'csv'. Defaults to 'xml'. - Format to use when exporting. Available choices are 'xml' or 'csv'. Defaults to 'xml'. - Exports the content of a database to standard output in the specified format. Exports the content of a database to standard output in the specified format. @@ -8216,18 +8711,6 @@ Kernel: %3 %4 file empty file empty - - malformed string - malformed string - - - missing closing quote - missing closing quote - - - %1: (row, col) %2,%3 - %1: (row, col) %2,%3 - AES 256-bit AES 256-bit @@ -8471,11 +8954,12 @@ Kernel: %3 %4 Set the key file for the database. This option is deprecated, use --set-key-file instead. - + Set the key file for the database. +This option is deprecated, use --set-key-file instead. Databases have been locked. - + Databases have been locked. Attestation not supported @@ -8672,13 +9156,89 @@ This option is deprecated, use --set-key-file instead. Shortcuts - Unsupported KDF type, cannot decrypt json file + Unknown passkeys error + Unknown passkeys error + + + Invalid KDF iterations, cannot decrypt json file + Invalid KDF iterations, cannot decrypt json file + + + Unsupported format, ensure your Bitwarden export is password-protected + Unsupported format, ensure your Bitwarden export is password-protected + + + Only PBKDF and Argon2 are supported, cannot decrypt json file + Only PBKDF and Argon2 are supported, cannot decrypt json file + + + Reset Shortcuts + Reset Shortcuts + + + Double click an action to change its shortcut + Double click an action to change its shortcut + + + Filter... + Filter... + + + Shortcut Conflict + Shortcut Conflict + + + Shortcut %1 conflicts with '%2'. Overwrite shortcut? + Shortcut %1 conflicts with '%2'. Overwrite shortcut? + + + Cannot generate valid passphrases because the wordlist is too short + Cannot generate valid passphrases because the wordlist is too short + + + Encrypted files are not supported. + Encrypted files are not supported. + + + Proton Pass Import + Proton Pass Import + + + Delete plugin data? + Delete plugin data? + + + Delete plugin data from Entry(s)? + Delete plugin data from Entry(s)?Delete plugin data from Entry(s)? + + + Passkey + Passkey + + + Format to use when exporting. Available choices are 'xml', 'csv' or 'html'. Defaults to 'xml'. - Unknown passkeys error + start minimized to the system tray + + malformed string, possible unescaped delimiter + + + + missing closing delimiter + + + + %1, row: %2, column: %3 + + + + Tags + Tags + QtIOCompressor @@ -8714,6 +9274,37 @@ This option is deprecated, use --set-key-file instead. Internal zlib error: + + RemoteHandler + + Command `%1` did not finish in time. Process was killed. + Command `%1` did not finish in time. Process was killed. + + + Failed to upload merged database. Command `%1` did not finish in time. Process was killed. + Failed to upload merged database. Command `%1` did not finish in time. Process was killed. + + + Invalid download parameters provided. + Invalid download parameters provided. + + + Command `%1` failed to download database. + Command `%1` failed to download database. + + + Invalid database pointer or upload parameters provided. + Invalid database pointer or upload parameters provided. + + + Command `%1` exited with status code: %2 + Command `%1` exited with status code: %2 + + + Failed to upload merged database. Command `%1` exited with status code: %2 + Failed to upload merged database. Command `%1` exited with status code: %2 + + ReportsWidgetBrowserStatistics @@ -8780,6 +9371,10 @@ This option is deprecated, use --set-key-file instead. Exclude from reports Exclude from reports + + Expire Entry(s)… + Expire Entry(s)…Expire Entry(s)… + Only show entries that have a URL Only show entries that have a URL @@ -8796,36 +9391,33 @@ This option is deprecated, use --set-key-file instead. (Expired) (Expired) + + Delete plugin data from Entry(s)… + Delete plugin data from Entry(s)…Delete plugin data from Entry(s)… + ReportsWidgetHealthcheck - Hover over reason to show additional details. Double-click entries to edit. - Hover over reason to show additional details. Double-click entries to edit. + Show expired entries + Show expired entries - Bad - Password quality - Bad + (Expired) + (Expired) + + + Hover over reason to show additional details. Double-click entries to edit. + Hover over reason to show additional details. Double-click entries to edit. Bad — password must be changed Bad — password must be changed - - Poor - Password quality - Poor - Poor — password should be changed Poor — password should be changed - - Weak - Password quality - Weak - Weak — consider changing the password Weak — consider changing the password @@ -8874,18 +9466,14 @@ This option is deprecated, use --set-key-file instead. Exclude from reports Exclude from reports - - Show expired entries - Show expired entries + + Expire Entry(s)… + Expire Entry(s)…Expire Entry(s)… Show entries that have been excluded from reports Show entries that have been excluded from reports - - (Expired) - (Expired) - ReportsWidgetHibp @@ -8981,6 +9569,10 @@ This option is deprecated, use --set-key-file instead. Exclude from reports Exclude from reports + + Expire Entry(s)… + Expire Entry(s)…Expire Entry(s)… + ReportsWidgetPasskeys @@ -9038,15 +9630,15 @@ This option is deprecated, use --set-key-file instead. The passkey file will be vulnerable to theft and unauthorized use, if left unsecured. Are you sure you want to continue? - + The passkey file will be vulnerable to theft and unauthorized use, if left unsecured. Are you sure you want to continue? Please wait, list of entries with passkeys is being updated… - + Please wait, list of entries with passkeys is being updated… No entries with passkeys. - + No entries with passkeys. @@ -9222,6 +9814,14 @@ This option is deprecated, use --set-key-file instead. No agent running, cannot list identities. No agent running. Cannot list identities. + + Failed to remove all SSH identities from agent. + Failed to remove all SSH identities from agent. + + + All SSH identities removed from agent. + All SSH identities removed from agent. + SearchHelpWidget @@ -9396,11 +9996,11 @@ This option is deprecated, use --set-key-file instead. <html><head/><body><p>This setting does not override disabling recycle bin prompts </p></body></html> - + <html><head/><body><p>This setting does not override disabling recycle bin prompts </p></body></html> <html><head/><body><p>This improves compatibility with certain applications which search for password without unlocking the database first.</p><p>But enabling this may also crash the client if the database can not be unlocked within a certain timeout. (Usually 25s, but may be a different value set in applications.) </p></body></html> - + <html><head/><body><p>This improves compatibility with certain applications which search for password without unlocking the database first.</p><p>But enabling this may also crash the client if the database can not be unlocked within a certain timeout. (Usually 25s, but may be a different value set in applications.) </p></body></html> @@ -9507,29 +10107,6 @@ This option is deprecated, use --set-key-file instead. Export to %1 - - ShortcutSettingsWidget - - Double click an action to change its shortcut - Double click an action to change its shortcut - - - Shortcut Conflict - Shortcut Conflict - - - Filter... - Filter... - - - Shortcut %1 conflicts with '%2'. Overwrite shortcut? - Shortcut %1 conflicts with '%2'. Overwrite shortcut? - - - Reset Shortcuts - Reset Shortcuts - - TagModel @@ -9818,14 +10395,18 @@ Example: JBSWY3DPEHPK3PXP No hardware keys detected No hardware keys detected - - <p>If you own a <a href="https://www.yubico.com/">YubiKey</a> or <a href="https://onlykey.io">OnlyKey</a>, you can use it for additional security.</p><p>The key requires one of its slots to be programmed as <a href="https://docs.yubico.com/yesdk/users-manual/application-otp/challenge-response.html">HMAC-SHA1 Challenge-Response</a>.</p> - <p>If you own a <a href="https://www.yubico.com/">YubiKey</a> or <a href="https://onlykey.io">OnlyKey</a>, you can use it for additional security.</p><p>The key requires one of its slots to be programmed as <a href="https://docs.yubico.com/yesdk/users-manual/application-otp/challenge-response.html">HMAC-SHA1 Challenge-Response</a>.</p> - Refresh hardware keys Refresh hardware keys + + <p>If you own a <a href="https://www.yubico.com/">YubiKey</a> or <a href="https://onlykey.io">OnlyKey</a>, you can use it for additional security.</p><p>The key requires one of its slots to be programmed with <a href="https://keepassxc.org/docs/#faq-yubikey-howto">Challenge-Response</a>.</p> + <p>If you own a <a href="https://www.yubico.com/">YubiKey</a> or <a href="https://onlykey.io">OnlyKey</a>, you can use it for additional security.</p><p>The key requires one of its slots to be programmed with <a href="https://keepassxc.org/docs/#faq-yubikey-howto">Challenge-Response</a>.</p> + + + Hardware keys found, but no slots are configured + Hardware keys found, but no slots are configured + YubiKeyInterfacePCSC diff --git a/share/translations/keepassxc_en_US.ts b/share/translations/keepassxc_en_US.ts index 9df7c9a4f..334f79c29 100644 --- a/share/translations/keepassxc_en_US.ts +++ b/share/translations/keepassxc_en_US.ts @@ -217,18 +217,50 @@ You must restart the application to set the new language. Would you like to restart now? You must restart the application to set the new language. Would you like to restart now? - - Reset Settings? - Reset Settings? - - - Are you sure you want to reset all general and security settings to default? - Are you sure you want to reset all general and security settings to default? - Select backup storage directory Select backup storage directory + + Confirm Reset + Confirm Reset + + + Are you sure you want to reset all settings to default? + Are you sure you want to reset all settings to default? + + + Import KeePassXC Settings + Import KeePassXC Settings + + + Failed to import settings from %1, not a valid settings file. + Failed to import settings from %1, not a valid settings file. + + + Export KeePassXC Settings + Export KeePassXC Settings + + + Small + Small + + + Normal + Normal + + + Medium + Medium + + + Large + Large + + + Custom + Custom + ApplicationSettingsWidgetGeneral @@ -280,25 +312,6 @@ Include beta releases when checking for updates Include beta releases when checking for updates - - On database unlock, show entries that - On database unlock, show entries that - - - have expired - On database unlock, show entries that... - have expired - - - days - On database unlock, show entries that will expire within %1 days - days - - - will expire within - On database unlock, show entries that... - will expire within - File Management File Management @@ -323,22 +336,10 @@ Backup database file before saving Backup database file before saving - - Backup destination - Backup destination - - - Specifies the database backup file location. Occurrences of "{DB_FILENAME}" are replaced with the filename of the saved database without extension. {TIME:<format>} is replaced with the backup time, see https://doc.qt.io/qt-5/qdatetime.html#toString. <format> defaults to format string "dd_MM_yyyy_hh-mm-ss". - Specifies the database backup file location. Occurrences of "{DB_FILENAME}" are replaced with the filename of the saved database without extension. {TIME:<format>} is replaced with the backup time, see https://doc.qt.io/qt-5/qdatetime.html#toString. <format> defaults to format string "dd_MM_yyyy_hh-mm-ss". - {DB_FILENAME}.old.kdbx {DB_FILENAME}.old.kdbx - - Choose... - Choose... - Use alternative saving method (may solve problems with Dropbox, Google Drive, GVFS, etc.) Use alternative saving method (may solve problems with Dropbox, Google Drive, GVFS, etc.) @@ -505,6 +506,71 @@ Remember last typed entry for: Remember last typed entry for: + + On database unlock, show entries that will expire within + On database unlock, show entries that will expire within + + + On database unlock, show entries that will expire within + On database unlock, show entries that will expire within + + + days + number of days warning for password expiration + days + + + Destination format: + Destination format: + + + <html><head/><body><p><span style=" font-weight:600;">{DB_FILENAME}</span> is replaced with the filename of the saved database without extension</p><p><span style=" font-weight:600;">{TIME:&lt;format&gt;}</span> is replaced with the specified time format (default: dd_MM_yyyy_hh-mm-ss)</p><p>See the User Guide for more details</p></body></html> + <html><head/><body><p><span style=" font-weight:600;">{DB_FILENAME}</span> is replaced with the filename of the saved database without extension</p><p><span style=" font-weight:600;">{TIME:&lt;format&gt;}</span> is replaced with the specified time format (default: dd_MM_yyyy_hh-mm-ss)</p><p>See the User Guide for more details</p></body></html> + + + Choose folder... + Choose folder... + + + Show confirmation before moving entries to recycle bin + Show confirmation before moving entries to recycle bin + + + Copy data on double clicking field in entry view + Copy data on double clicking field in entry view + + + Show toolbar + Show toolbar + + + Show the menu bar by pressing the Alt key + Show the menu bar by pressing the Alt key + + + Show menubar + Show menubar + + + Import settings… + Import settings… + + + Export settings… + Export settings… + + + Open browser on double clicking URL field in entry view + Open browser on double clicking URL field in entry view + + + Font size: + Font size: + + + Font size selection + Font size selection + ApplicationSettingsWidgetSecurity @@ -570,18 +636,6 @@ Hide passwords in the entry preview panel Hide passwords in the entry preview panel - - Hide entry notes by default - Hide entry notes by default - - - Move entries to recycle bin without confirmation - Move entries to recycle bin without confirmation - - - Enable double click to copy the username/password entry columns - Enable double click to copy the username/password entry columns - Privacy Privacy @@ -594,6 +648,18 @@ Hide TOTP in the entry preview panel Hide TOTP in the entry preview panel + + Lock databases when switching user + Lock databases when switching user + + + Lock Options + Lock Options + + + Hide notes in the entry preview panel + Hide notes in the entry preview panel + AutoType @@ -641,20 +707,6 @@ Entry does not have attribute for PICKCHARS: %1 Entry does not have attribute for PICKCHARS: %1 - - Invalid conversion type: %1 - Invalid conversion type: %1 - - - Invalid conversion syntax: %1 - Invalid conversion syntax: %1 - - - Invalid regular expression syntax %1 -%2 - Invalid regular expression syntax %1 -%2 - Invalid placeholder: %1 Invalid placeholder: %1 @@ -714,7 +766,7 @@ Trying to send invalid keyboard symbol. - + Trying to send invalid keyboard symbol. @@ -822,7 +874,7 @@ Ctrl+4 - Use Virtual Keyboard (Windows Only)</p> Undo - + Undo @@ -886,24 +938,25 @@ Please select the correct database for saving credentials. Add to existing entry - + Add to existing entry Existing passkey found. Do you want to register a new passkey for: - + Existing passkey found. +Do you want to register a new passkey for: Select the existing passkey and press Update to replace it. - + Select the existing passkey and press Update to replace it. Authenticate passkey credentials for: - + Authenticate passkey credentials for: Do you want to register a passkey for: - + Do you want to register a passkey for: @@ -988,16 +1041,17 @@ Do you want to delete the entry? Register a new passkey to this entry: - + Register a new passkey to this entry: KeePassXC - Update passkey - + KeePassXC - Update passkey Entry already has a passkey. Do you want to overwrite the passkey in %1 - %2? - + Entry already has a passkey. +Do you want to overwrite the passkey in %1 - %2? Register @@ -1022,10 +1076,6 @@ Do you want to overwrite the passkey in %1 - %2? General General - - Browsers installed as snaps are currently not supported. - Browsers installed as snaps are currently not supported. - Enable integration for these browsers: Enable integration for these browsers: @@ -1197,18 +1247,6 @@ Do you want to overwrite the passkey in %1 - %2? Custom extension ID Custom extension ID - - Due to Snap sandboxing, you must run a script to enable browser integration.<br />You can obtain this script from %1 - Due to Snap sandboxing, you must run a script to enable browser integration.<br />You can obtain this script from %1 - - - KeePassXC-Browser is needed for the browser integration to work. <br />Download it for %1 and %2 and %3. %4 - KeePassXC-Browser is needed for the browser integration to work. <br />Download it for %1 and %2 and %3. %4 - - - Please see special instructions for browser extension use below - Please see special instructions for browser extension use below - Executable Files Executable Files @@ -1251,11 +1289,19 @@ Do you want to overwrite the passkey in %1 - %2? Allows using insecure http://localhost with passkeys for testing purposes. - + Allows using insecure http://localhost with passkeys for testing purposes. Allow using localhost with passkeys - + Allow using localhost with passkeys + + + KeePassXC-Browser is needed for the browser integration to work. <br />Download it for %1 and %2 and %3. + KeePassXC-Browser is needed for the browser integration to work. <br />Download it for %1 and %2 and %3. + + + Browsers installed using Snap or Flatpak are not supported with exception to Firefox installed using Snap. + Browsers installed using Snap or Flatpak are not supported with exception to Firefox installed using Snap. @@ -1399,6 +1445,20 @@ Do you want to overwrite the passkey in %1 - %2? Imported from CSV file: %1 Imported from CSV file: %1 + + No Title Selected + No Title Selected + + + No title column was selected, entries will be hard to tell apart. +Are you sure you want to import? + No title column was selected, entries will be hard to tell apart. +Are you sure you want to import? + + + Tags + Tags + CsvParserModel @@ -1462,6 +1522,14 @@ Backup database located at %2 Recycle Bin Recycle Bin + + Database file read error. + Database file read error. + + + No file path was provided. + No file path was provided. + DatabaseOpenDialog @@ -1610,14 +1678,6 @@ To prevent this error from appearing, you must go to "Database Settings / S <p>In addition to a password, you can use a secret file to enhance the security of your database. This file can be generated in your database's security settings.</p><p>This is <strong>not</strong> your *.kdbx database file!</p> <p>In addition to a password, you can use a secret file to enhance the security of your database. This file can be generated in your database's security settings.</p><p>This is <strong>not</strong> your *.kdbx database file!</p> - - Click to add a key file. - Click to add a key file. - - - <a href="#" style="text-decoration: underline">I have a key file</a> - <a href="#" style="text-decoration: underline">I have a key file</a> - Use hardware key [Serial: %1] Use hardware key [Serial: %1] @@ -1644,7 +1704,7 @@ Are you sure you want to continue with this file?. The file you selected looks like a database file. A database file is NOT a key file! -Are you sure you want to continue with this file?. +Are you sure you want to continue with this file? No hardware keys found. @@ -1654,6 +1714,18 @@ Are you sure you want to continue with this file?. Refresh Hardware Keys Refresh Hardware Keys + + Click to add a key file. + Click to add a key file. + + + <a href="#" style="text-decoration: underline">I have a key file</a> + <a href="#" style="text-decoration: underline">I have a key file</a> + + + Hardware keys found, but no slots are configured. + Hardware keys found, but no slots are configured. + DatabaseSettingWidgetMetaData @@ -1688,6 +1760,22 @@ Are you sure you want to continue with this file?. Maintenance Maintenance + + KeeShare + KeeShare + + + Secret Service Integration + Secret Service Integration + + + Remote Sync + + + + Database Settings: %1 + + DatabaseSettingsWidgetBrowser @@ -1859,12 +1947,12 @@ Are you sure you want to continue without a password? Weak password - You must enter a stronger password to protect your database. - + This is a weak password! For better protection of your secrets, you should choose a stronger password. + This is a weak password! For better protection of your secrets, you should choose a stronger password. - This is a weak password! For better protection of your secrets, you should choose a stronger password. - + The provided password does not meet the minimum quality requirement. + The provided password does not meet the minimum quality requirement. @@ -2007,11 +2095,11 @@ If you keep this number, your database will not be protected from brute force at Encryption Settings: - + Encryption Settings: Basic - + Basic Advanced @@ -2149,15 +2237,15 @@ removed from the database. Autosave delay since last change - + Autosave delay since last change Autosave delay - + Autosave delay Autosave delay since last change in minutes - + Autosave delay since last change in minutes min @@ -2165,7 +2253,51 @@ removed from the database. Autosave delay since last change checkbox - + Autosave delay since last change checkbox + + + Public Database Metadata + Public Database Metadata + + + Warning: the following settings are not encrypted. + Warning: the following settings are not encrypted. + + + Display name: + Display name: + + + Publically visible display name used on the unlock dialog + Publically visible display name used on the unlock dialog + + + Database public display name + Database public display name + + + Display color: + Display color: + + + Publically visible color used on the unlock dialog + Publically visible color used on the unlock dialog + + + Database public display color chooser + Database public display color chooser + + + Clear + Clear + + + Display icon: + Display icon: + + + Select Database Icon + Select Database Icon @@ -2262,6 +2394,129 @@ removed from the database. Database description field + + DatabaseSettingsWidgetRemote + + Sync Commands + + + + Remove + Remove + + + Command Settings + + + + Name + Name + + + Save + Save + + + Download + + + + Command: + + + + Download command field + + + + e.g.: "sftp user@hostname" or "scp user@hostname:DatabaseOnRemote.kdbx {TEMP_DATABASE}" + + + + Input: + + + + Download input field + + + + Upload + + + + Upload command field + + + + e.g.: "sftp user@hostname" or "scp {TEMP_DATABASE} user@hostname:DatabaseOnRemote.kdbx" + + + + Upload input field + + + + Name cannot be empty. + + + + Test + + + + Download command cannot be empty. + + + + Download failed with error: %1 + + + + Download finished, but file %1 could not be found. + + + + Download successful. + + + + Save Remote Settings + + + + You have unsaved changes. Do you want to save them? + + + + e.g.: +get DatabaseOnRemote.kdbx {TEMP_DATABASE} +exit +--- +{TEMP_DATABASE} is used as placeholder to store the database in a temporary location +The command has to exit. In case of `sftp` as last command `exit` has to be sent + + + + + e.g.: +put {TEMP_DATABASE} DatabaseOnRemote.kdbx +exit +--- +{TEMP_DATABASE} is used as placeholder to store the database in a temporary location +The command has to exit. In case of `sftp` as last command `exit` has to be sent + + + + + Timeout: + + + + seconds + seconds + + DatabaseTabWidget @@ -2335,6 +2590,11 @@ This is definitely a bug, please report it to the developers. Database tab name modifier %1 [Locked] + + %1 [Temporary] + Database tab name modifier + + DatabaseWidget @@ -2458,26 +2718,6 @@ Save changes? File has changed File has changed - - The database file has changed. Do you want to load the changes? - The database file has changed. Do you want to load the changes? - - - Merge Request - Merge Request - - - The database file has changed and you have unsaved changes. -Do you want to merge your changes? - The database file has changed and you have unsaved changes. -Do you want to merge your changes? - - - Could not open the new database file while attempting to autoreload. -Error: %1 - Could not open the new database file while attempting to autoreload. -Error: %1 - Disable safe saves? Disable safe saves? @@ -2529,6 +2769,86 @@ Disable safe saves and try again? Database tab name modifier %1 [New Database] + + Remote Sync did not contain any download or upload commands. + + + + Remote sync '%1' completed successfully! + + + + Remote sync '%1' failed: %2 + + + + Error while saving database %1: %2 + + + + Downloading... + Downloading... + + + Uploading... + + + + Syncing... + + + + Remove passkey from entry + Remove passkey from entry + + + Do you want to remove the passkey from this entry? + Do you want to remove the passkey from this entry? + + + The database file "%1" was modified externally + The database file "%1" was modified externally + + + Do you want to load the changes? + Do you want to load the changes? + + + Reload database + Reload database + + + Reloading database… + Reloading database… + + + Reload canceled + Reload canceled + + + Reload successful + Reload successful + + + Reload pending user action… + Reload pending user action… + + + The database file "%1" was modified externally.<br>How would you like to proceed?<br><br>Merge all changes<br>Ignore the changes on disk until save<br>Discard unsaved changes + The database file "%1" was modified externally.<br>How would you like to proceed?<br><br>Merge all changes<br>Ignore the changes on disk until save<br>Discard unsaved changes + + + The database file "%1" was modified externally.<br>How would you like to proceed?<br><br>Merge all changes then save<br>Overwrite the changes on disk<br>Discard unsaved changes + The database file "%1" was modified externally.<br>How would you like to proceed?<br><br>Merge all changes then save<br>Overwrite the changes on disk<br>Discard unsaved changes + + + Database file overwritten. + Database file overwritten. + + + Database file on disk cannot be unlocked with current credentials.<br>Enter new credentials and/or present hardware key to continue. + Database file on disk cannot be unlocked with current credentials.<br>Enter new credentials and/or present hardware key to continue. + EditEntryWidget @@ -2580,10 +2900,6 @@ Disable safe saves and try again? n/a n/a - - (encrypted) - (encrypted) - Select private key Select private key @@ -2686,6 +3002,10 @@ Would you like to correct it? %n year(s) %n year%n years + + Failed to decrypt SSH key, ensure password is correct. + Failed to decrypt SSH key, ensure password is correct. + EditEntryWidgetAdvanced @@ -2857,18 +3177,10 @@ Would you like to correct it? Skip Auto-Submit for this entry Skip Auto-Submit for this entry - - Only send this setting to the browser for HTTP Auth dialogs. If enabled, normal login forms will not show this entry for selection. - Only send this setting to the browser for HTTP Auth dialogs. If enabled, normal login forms will not show this entry for selection. - Use this entry only with HTTP Basic Auth Use this entry only with HTTP Basic Auth - - Do not send this setting to the browser for HTTP Auth dialogs. If enabled, HTTP Auth dialogs will not show this entry for selection. - Do not send this setting to the browser for HTTP Auth dialogs. If enabled, HTTP Auth dialogs will not show this entry for selection. - Do not use this entry with HTTP Basic Auth Do not use this entry with HTTP Basic Auth @@ -2887,11 +3199,19 @@ Would you like to correct it? These settings affect the entry's behaviour with the browser extension. - + These settings affect the entry's behaviour with the browser extension. Additional URLs - + Additional URLs + + + Only send this entry to the browser for HTTP Auth dialogs. If enabled, normal login forms will not show this entry for selection. + Only send this entry to the browser for HTTP Auth dialogs. If enabled, normal login forms will not show this entry for selection. + + + Do not send this entry to the browser for HTTP Auth dialogs. If enabled, HTTP Auth dialogs will not show this entry for selection. + Do not send this entry to the browser for HTTP Auth dialogs. If enabled, HTTP Auth dialogs will not show this entry for selection. @@ -3080,7 +3400,7 @@ Would you like to correct it? Browser for key file - Browser for key file + Browse filesystem for key file Browse… @@ -3115,6 +3435,10 @@ Would you like to correct it? seconds seconds + + Clear agent + Clear agent + EditGroupWidget @@ -3557,6 +3881,24 @@ This may cause the affected plugins to malfunction. %1 - Clone %1 - Clone + + Passkey + Passkey + + + Invalid conversion type: %1 + Invalid conversion type: %1 + + + Invalid conversion syntax: %1 + Invalid conversion syntax: %1 + + + Invalid regular expression syntax %1 +%2 + Invalid regular expression syntax %1 +%2 + EntryAttachments @@ -3565,6 +3907,21 @@ This may cause the affected plugins to malfunction. Cannot open file "%1" + + EntryAttachmentsDialog + + Form + Form + + + File name + File name + + + File contents... + File contents... + + EntryAttachmentsModel @@ -3602,14 +3959,6 @@ This may cause the affected plugins to malfunction. Remove Remove - - Rename selected attachment - Rename selected attachment - - - Rename - Rename - Open selected attachment Open selected attachment @@ -3725,6 +4074,18 @@ Would you like to overwrite the existing attachment? Attachment "%1" already exists. Would you like to overwrite the existing attachment? + + New + New + + + Preview + Preview + + + Failed to preview an attachment: Attachment not found + Failed to preview an attachment: Attachment not found + EntryAttributesModel @@ -3921,7 +4282,11 @@ Would you like to overwrite the existing attachment? Background Color - + Background Color + + + Group Path + Group Path @@ -4318,6 +4683,14 @@ You can enable the DuckDuckGo website icon service in the security section of th Url Url + + Could not load key file. + + + + Could not open remote database. Password or key file may be incorrect. + + ImportWizardPageSelect @@ -4343,7 +4716,7 @@ You can enable the DuckDuckGo website icon service in the security section of th Import Into: - + Import Into: New Database @@ -4351,35 +4724,35 @@ You can enable the DuckDuckGo website icon service in the security section of th No unlocked databases available - + No unlocked databases available Existing Database: - + Existing Database: Import File: - + Import File: Comma Separated Values (.csv) - + Comma Separated Values (.csv) 1Password Export (.1pux) - + 1Password Export (.1pux) 1Password Vault (.opvault) - + 1Password Vault (.opvault) Bitwarden (.json) - + Bitwarden (.json) KeePass 1 Database (.kdb) - + KeePass 1 Database (.kdb) Open OPVault @@ -4387,7 +4760,7 @@ You can enable the DuckDuckGo website icon service in the security section of th Select import file - + Select import file All files @@ -4403,24 +4776,62 @@ You can enable the DuckDuckGo website icon service in the security section of th Comma Separated Values - + Comma Separated Values 1Password Export - + 1Password Export Bitwarden JSON Export - + Bitwarden JSON Export 1Password Vault - + 1Password Vault KeePass1 Database + KeePass1 Database + + + Proton Pass (.json) + Proton Pass (.json) + + + Proton Pass JSON Export + Proton Pass JSON Export + + + Temporary Database + + Command: + + + + e.g.: "sftp user@hostname" or "scp user@hostname:DatabaseOnRemote.kdbx {TEMP_DATABASE}" + + + + Input: + + + + e.g.: +get DatabaseOnRemote.kdbx {TEMP_DATABASE} +exit +--- +{TEMP_DATABASE} is used as placeholder to store the database in a temporary location +The command has to exit. In case of `sftp` as last commend `exit` has to be sent + + + + + Remote Database (.kdbx) + Remote Database (.kdbx) + KMessageWidget @@ -5506,7 +5917,7 @@ Are you sure you want to continue with this file? Show Menubar - + Show Menubar Show Toolbar @@ -5561,12 +5972,6 @@ This version is not meant for production use. Expect some bugs and minor issues, this version is meant for testing purposes. NOTE: You are using a pre-release version of KeePassXC. Expect some bugs and minor issues, this version is meant for testing purposes. - - - WARNING: Your Qt version may cause KeePassXC to crash with an On-Screen Keyboard. -We recommend you use the AppImage available on our downloads page. - WARNING: Your Qt version may cause KeePassXC to crash with an On-Screen Keyboard. -We recommend you use the AppImage available on our downloads page. No Tags @@ -5622,22 +6027,26 @@ We recommend you use the AppImage available on our downloads page. 1Password 1PUX... - + 1Password 1PUX... Import a 1Password 1PUX file - + Import a 1Password 1PUX file Import… - + Import… Passkeys… - + Passkeys… Import Passkey + Import Passkey + + + Remote S&ync… @@ -5650,11 +6059,11 @@ We recommend you use the AppImage available on our downloads page. Open Database - + Open Database Create Database - + Create Database Merge From Database @@ -5744,6 +6153,10 @@ We recommend you use the AppImage available on our downloads page. Show Password Generator + + Remove Passkey From Entry + Remove Passkey From Entry + Perform Auto-Type: {USERNAME} @@ -5806,7 +6219,7 @@ We recommend you use the AppImage available on our downloads page. Empty Recycle Bin - + Empty Recycle Bin Open Donation Website @@ -5858,7 +6271,7 @@ We recommend you use the AppImage available on our downloads page. Toggle Show Menubar - + Toggle Show Menubar Toggle Show Toolbar @@ -5888,6 +6301,34 @@ We recommend you use the AppImage available on our downloads page. Toggle Allow Screen Capture + + Show Group Panel + Show Group Panel + + + Toggle Show Group Panel + Toggle Show Group Panel + + + Setup Remote Sync… + + + + Password Generator + Password Generator + + + E&xpire Entry… + E&xpire Entry… + + + Clear SSH Agent + Clear SSH Agent + + + Clear all identities in ssh-agent + Clear all identities in ssh-agent + ManageDatabase @@ -6038,6 +6479,25 @@ We recommend you use the AppImage available on our downloads page. Please fill in the display name and an optional description for your new database: + + NewEntryAttachmentsDialog + + Attachment name cannot be empty + Attachment name cannot be empty + + + Attachment with the same name already exists + Attachment with the same name already exists + + + Save attachment + Save attachment + + + New entry attachment + New entry attachment + + NixUtils @@ -6225,6 +6685,10 @@ We recommend you use the AppImage available on our downloads page. Unexpected EOF when writing private key Unexpected EOF when writing private key + + (encrypted) + (encrypted) + OpenSSHKeyGenDialog @@ -6249,19 +6713,19 @@ We recommend you use the AppImage available on our downloads page. PasskeyExportDialog KeePassXC - Passkey Export - + KeePassXC - Passkey Export Filenames will be generated with title and .passkey file extension. - + Filenames will be generated with title and .passkey file extension. Export entries - + Export entries Export Selected - + Export Selected Cancel @@ -6269,43 +6733,45 @@ We recommend you use the AppImage available on our downloads page. Export to folder - + Export to folder Export the following passkey entries. - + Export the following passkey entries. PasskeyExporter KeePassXC: Passkey Export - + KeePassXC: Passkey Export File "%1.passkey" already exists. Do you want to overwrite it? - + File "%1.passkey" already exists. +Do you want to overwrite it? + Cannot open file - + Cannot open file Cannot open file "%1" for writing. - + Cannot open file "%1" for writing. Cannot write to file - + Cannot write to file PasskeyImportDialog KeePassXC - Passkey Import - + KeePassXC - Passkey Import Username: %1 @@ -6317,11 +6783,11 @@ Do you want to overwrite it? Database - + Database Import Passkey - + Import Passkey Import @@ -6337,7 +6803,7 @@ Do you want to overwrite it? Create new entry - + Create new entry Relying Party: %1 @@ -6345,22 +6811,22 @@ Do you want to overwrite it? Import the following passkey: - + Import the following passkey: Import the following passkey to this entry: - + Import the following passkey to this entry: Default passkeys group (Imported Passkeys) - + Default passkeys group (Imported Passkeys) PasskeyImporter Passkey file - + Passkey file All files @@ -6368,33 +6834,35 @@ Do you want to overwrite it? Cannot open file - + Cannot open file Cannot open file "%1" for reading. - + Cannot open file "%1" for reading. Open passkey file - + Open passkey file Cannot import passkey - + Cannot import passkey Cannot import passkey file "%1". Data is missing. - + Cannot import passkey file "%1". Data is missing. Cannot import passkey file "%1". The following data is missing: %2 - + Cannot import passkey file "%1". +The following data is missing: +%2 Cannot import passkey file "%1". Private key is missing or malformed. - + Cannot import passkey file "%1". Private key is missing or malformed. @@ -6575,10 +7043,6 @@ The following data is missing: Also choose from: Also choose from: - - Excluded characters: "0", "1", "l", "I", "O", "|", "﹒" - Excluded characters: "0", "1", "l", "I", "O", "|", "﹒" - Exclude look-alike characters Exclude look-alike characters @@ -6603,10 +7067,6 @@ The following data is missing: Word Count: Word Count: - - Character Count: - Character Count: - Word Case: Word Case: @@ -6619,10 +7079,6 @@ The following data is missing: Add custom wordlist Add custom wordlist - - character - character - Close Close @@ -6729,6 +7185,22 @@ Do you want to overwrite it? Special Characters Special Characters + + passwordLength + passwordLength + + + Characters: %1 + Characters: %1 + + + MIXED case + MIXED case + + + Excluded characters: "0", "1", "l", "I", "O", "|", "﹒", "B", "8", "G", "6" + Excluded characters: "0", "1", "l", "I", "O", "|", "﹒", "B", "8", "G", "6" + PasswordWidget @@ -6796,6 +7268,21 @@ Do you want to overwrite it? Press &Tab between characters + + PreviewEntryAttachmentsDialog + + Preview entry attachment + Preview entry attachment + + + No preview available + No preview available + + + Image format not supported + Image format not supported + + QMessageBox @@ -6836,7 +7323,7 @@ Do you want to overwrite it? Continue with weak password - + Continue with weak password @@ -7474,10 +7961,6 @@ Do you want to overwrite it? Invalid word count %1 Invalid word count %1 - - The word list is too small (< 1000 items) - The word list is too small (< 1000 items) - Title for the entry. Title for the entry. @@ -7622,10 +8105,6 @@ Do you want to overwrite it? Exit interactive mode. Exit interactive mode. - - Format to use when exporting. Available choices are 'xml' or 'csv'. Defaults to 'xml'. - Format to use when exporting. Available choices are 'xml' or 'csv'. Defaults to 'xml'. - Exports the content of a database to standard output in the specified format. Exports the content of a database to standard output in the specified format. @@ -8214,18 +8693,6 @@ Kernel: %3 %4 file empty file empty - - malformed string - malformed string - - - missing closing quote - missing closing quote - - - %1: (row, col) %2,%3 - %1: (row, col) %2,%3 - AES 256-bit AES 256-bit @@ -8460,48 +8927,49 @@ Kernel: %3 %4 Access to all entries is denied - + Access to all entries is denied allow screenshots and app recording (Windows/macOS) - + allow screenshots and app recording (Windows/macOS) Set the key file for the database. This option is deprecated, use --set-key-file instead. - + Set the key file for the database. +This option is deprecated, use --set-key-file instead. Databases have been locked. - + Databases have been locked. Attestation not supported - + Attestation not supported Credential is excluded - + Credential is excluded Passkeys request canceled - + Passkeys request canceled Invalid user verification - + Invalid user verification Empty public key - + Empty public key Invalid URL provided - + Invalid URL provided Passkeys - + Passkeys AES initialization failed @@ -8561,101 +9029,101 @@ This option is deprecated, use --set-key-file instead. Origin is empty or not allowed - + Origin is empty or not allowed Effective domain is not a valid domain - + Effective domain is not a valid domain Origin and RP ID do not match - + Origin and RP ID do not match No supported algorithms were provided - + No supported algorithms were provided Wait for timer to expire - + Wait for timer to expire Challenge is shorter than required minimum length - + Challenge is shorter than required minimum length user.id does not match the required length - + user.id does not match the required length Favorite Tag for favorite entries - + Favorite File does not exist. - + File does not exist. Cannot open file: %1 - + Cannot open file: %1 Cannot parse file: %1 at position %2 - + Cannot parse file: %1 at position %2 Failed to decrypt json file: %1 - + Failed to decrypt json file: %1 Invalid encKeyValidation field - + Invalid encKeyValidation field Invalid cipher list within encKeyValidation field - + Invalid cipher list within encKeyValidation field Wrong password - + Wrong password Invalid encrypted data field - + Invalid encrypted data field Invalid cipher list within encrypted data field - + Invalid cipher list within encrypted data field Cannot initialize cipher - + Cannot initialize cipher Cannot decrypt data - + Cannot decrypt data Bitwarden Import - + Bitwarden Import Archived Tag for archived entries - + Archived Invalid 1PUX file format: Not a valid ZIP file. - + Invalid 1PUX file format: Not a valid ZIP file. Invalid 1PUX file format: Missing export.data - + Invalid 1PUX file format: Missing export.data 1Password Import - + 1Password Import Enter Shortcut @@ -8670,13 +9138,89 @@ This option is deprecated, use --set-key-file instead. - Unsupported KDF type, cannot decrypt json file + Unknown passkeys error + Unknown passkeys error + + + Invalid KDF iterations, cannot decrypt json file + Invalid KDF iterations, cannot decrypt json file + + + Unsupported format, ensure your Bitwarden export is password-protected + Unsupported format, ensure your Bitwarden export is password-protected + + + Only PBKDF and Argon2 are supported, cannot decrypt json file + Only PBKDF and Argon2 are supported, cannot decrypt json file + + + Reset Shortcuts - Unknown passkeys error + Double click an action to change its shortcut + + Filter... + + + + Shortcut Conflict + + + + Shortcut %1 conflicts with '%2'. Overwrite shortcut? + + + + Cannot generate valid passphrases because the wordlist is too short + Cannot generate valid passphrases because the wordlist is too short + + + Encrypted files are not supported. + Encrypted files are not supported. + + + Proton Pass Import + Proton Pass Import + + + Delete plugin data? + Delete plugin data? + + + Delete plugin data from Entry(s)? + Delete plugin data from Entry?Delete plugin data from Entries? + + + Passkey + Passkey + + + Format to use when exporting. Available choices are 'xml', 'csv' or 'html'. Defaults to 'xml'. + Format to use when exporting. Available choices are 'xml', 'csv' or 'html'. Defaults to 'xml'. + + + start minimized to the system tray + start minimized to the system tray + + + malformed string, possible unescaped delimiter + + + + missing closing delimiter + + + + %1, row: %2, column: %3 + + + + Tags + Tags + QtIOCompressor @@ -8712,6 +9256,37 @@ This option is deprecated, use --set-key-file instead. Internal zlib error: + + RemoteHandler + + Command `%1` did not finish in time. Process was killed. + + + + Failed to upload merged database. Command `%1` did not finish in time. Process was killed. + + + + Invalid download parameters provided. + + + + Command `%1` failed to download database. + + + + Invalid database pointer or upload parameters provided. + + + + Command `%1` exited with status code: %2 + + + + Failed to upload merged database. Command `%1` exited with status code: %2 + + + ReportsWidgetBrowserStatistics @@ -8778,52 +9353,53 @@ This option is deprecated, use --set-key-file instead. Exclude from reports Exclude from reports + + Expire Entry(s)… + Expire Entry…Expire Entries… + Only show entries that have a URL - + Only show entries that have a URL Only show entries that have been explicitly allowed or denied - + Only show entries that have been explicitly allowed or denied Show expired entries - + Show expired entries (Expired) - + (Expired) + + + Delete plugin data from Entry(s)… + Delete plugin data from Entry…Delete plugin data from Entries… ReportsWidgetHealthcheck - Hover over reason to show additional details. Double-click entries to edit. - Hover over reason to show additional details. Double-click entries to edit. + Show expired entries + Show expired entries - Bad - Password quality - Bad + (Expired) + (Expired) + + + Hover over reason to show additional details. Double-click entries to edit. + Hover over reason to show additional details. Double-click entries to edit. Bad — password must be changed Bad — password must be changed - - Poor - Password quality - Poor - Poor — password should be changed Poor — password should be changed - - Weak - Password quality - Weak - Weak — consider changing the password Weak — consider changing the password @@ -8872,17 +9448,13 @@ This option is deprecated, use --set-key-file instead. Exclude from reports Exclude from reports - - Show expired entries - + + Expire Entry(s)… + Expire Entry…Expire Entries… Show entries that have been excluded from reports - - - - (Expired) - + Show entries that have been excluded from reports @@ -8979,6 +9551,10 @@ This option is deprecated, use --set-key-file instead. Exclude from reports Exclude from reports + + Expire Entry(s)… + Expire Entry…Expire Entries… + ReportsWidgetPasskeys @@ -9020,15 +9596,15 @@ This option is deprecated, use --set-key-file instead. Relying Party - + Relying Party Show expired entries - + Show expired entries (Expired) - + (Expired) Export Confirmation @@ -9036,15 +9612,15 @@ This option is deprecated, use --set-key-file instead. The passkey file will be vulnerable to theft and unauthorized use, if left unsecured. Are you sure you want to continue? - + The passkey file will be vulnerable to theft and unauthorized use, if left unsecured. Are you sure you want to continue? Please wait, list of entries with passkeys is being updated… - + Please wait, list of entries with passkeys is being updated… No entries with passkeys. - + No entries with passkeys. @@ -9220,6 +9796,14 @@ This option is deprecated, use --set-key-file instead. No agent running, cannot list identities. No agent running, cannot list identities. + + Failed to remove all SSH identities from agent. + Failed to remove all SSH identities from agent. + + + All SSH identities removed from agent. + All SSH identities removed from agent. + SearchHelpWidget @@ -9394,11 +9978,11 @@ This option is deprecated, use --set-key-file instead. <html><head/><body><p>This setting does not override disabling recycle bin prompts </p></body></html> - + <html><head/><body><p>This setting does not override disabling recycle bin prompts </p></body></html> <html><head/><body><p>This improves compatibility with certain applications which search for password without unlocking the database first.</p><p>But enabling this may also crash the client if the database can not be unlocked within a certain timeout. (Usually 25s, but may be a different value set in applications.) </p></body></html> - + <html><head/><body><p>This improves compatibility with certain applications which search for password without unlocking the database first.</p><p>But enabling this may also crash the client if the database can not be unlocked within a certain timeout. (Usually 25s, but may be a different value set in applications.) </p></body></html> @@ -9505,29 +10089,6 @@ This option is deprecated, use --set-key-file instead. Export to %1 - - ShortcutSettingsWidget - - Double click an action to change its shortcut - - - - Shortcut Conflict - - - - Filter... - - - - Shortcut %1 conflicts with '%2'. Overwrite shortcut? - - - - Reset Shortcuts - - - TagModel @@ -9737,15 +10298,15 @@ Example: JBSWY3DPEHPK3PXP Create Database - + Create Database Open Database - + Open Database Import File - + Import File @@ -9817,12 +10378,16 @@ Example: JBSWY3DPEHPK3PXP No hardware keys detected - <p>If you own a <a href="https://www.yubico.com/">YubiKey</a> or <a href="https://onlykey.io">OnlyKey</a>, you can use it for additional security.</p><p>The key requires one of its slots to be programmed as <a href="https://docs.yubico.com/yesdk/users-manual/application-otp/challenge-response.html">HMAC-SHA1 Challenge-Response</a>.</p> - + Refresh hardware keys + Refresh hardware keys - Refresh hardware keys - + <p>If you own a <a href="https://www.yubico.com/">YubiKey</a> or <a href="https://onlykey.io">OnlyKey</a>, you can use it for additional security.</p><p>The key requires one of its slots to be programmed with <a href="https://keepassxc.org/docs/#faq-yubikey-howto">Challenge-Response</a>.</p> + <p>If you own a <a href="https://www.yubico.com/">YubiKey</a> or <a href="https://onlykey.io">OnlyKey</a>, you can use it for additional security.</p><p>The key requires one of its slots to be programmed with <a href="https://keepassxc.org/docs/#faq-yubikey-howto">Challenge-Response</a>.</p> + + + Hardware keys found, but no slots are configured + Hardware keys found, but no slots are configured @@ -9850,7 +10415,7 @@ Example: JBSWY3DPEHPK3PXP (NFC) %1 [%2] - Slot %3, %4 YubiKey display fields - + (NFC) %1 [%2] - Slot %3, %4 Press @@ -9902,12 +10467,12 @@ Example: JBSWY3DPEHPK3PXP %1 [%2] - Slot %3 YubiKey NEO display fields - + %1 [%2] - Slot %3 %1 [%2] - Slot %3, %4 YubiKey display fields - + %1 [%2] - Slot %3, %4 \ No newline at end of file diff --git a/share/translations/keepassxc_es.ts b/share/translations/keepassxc_es.ts index 41d45b75b..502575fa3 100644 --- a/share/translations/keepassxc_es.ts +++ b/share/translations/keepassxc_es.ts @@ -11,11 +11,11 @@ Report bugs at: <a href="https://github.com/keepassxreboot/keepassxc/issues" style="text-decoration: underline;">https://github.com</a> - Informe errores en: <a href="https://github.com/keepassxreboot/keepassxc/issues" style="text-decoration: underline;">https://github.com</a> + Informar de errores en: <a href="https://github.com/keepassxreboot/keepassxc/issues" style="text-decoration: underline;">https://github.com</a> KeePassXC is distributed under the terms of the GNU General Public License (GPL) version 2 or (at your option) version 3. - KeePassXC se distribuye bajo la Licencia Pública General de GNU (GPL) versión 2 o versión 3 (si así lo prefiere). + KeePassXC se distribuye bajo los términos de la Licencia Pública General de GNU (GPL) versión 2 o (a tu elección) versión 3. Project Maintainers: @@ -74,7 +74,7 @@ Command Line - Línea de órdenes + Línea de comandos Details @@ -217,24 +217,56 @@ You must restart the application to set the new language. Would you like to restart now? Debe reiniciar la aplicación para establecer el nuevo lenguage. ¿Desea reiniciar ahora? - - Reset Settings? - ¿Restablecer configuración? - - - Are you sure you want to reset all general and security settings to default? - predeterminado¿Desea restablecer toda la configuración general y de seguridad a sus valores por defecto? - Select backup storage directory Seleccionar la carpeta de copia de seguridad + + Confirm Reset + Confirmar Reinicio + + + Are you sure you want to reset all settings to default? + ¿Estás seguro de que quieres restablecer todos los ajustes por defecto? + + + Import KeePassXC Settings + Importar la configuración de KeePassXC + + + Failed to import settings from %1, not a valid settings file. + No se pudo importar la configuración de %1, no es un archivo de configuración válido. + + + Export KeePassXC Settings + Exportar la configuración de KeePassXC + + + Small + Pequeño + + + Normal + normal + + + Medium + mediano + + + Large + largo + + + Custom + Personalizado + ApplicationSettingsWidgetGeneral Basic Settings - configuración básica + Configuración básica Startup @@ -246,7 +278,7 @@ Automatically launch KeePassXC at system startup - Inicie automáticamente KeePassXC al arrancar el sistema + Iniciar automáticamente KeePassXC al arrancar el sistema Minimize window at application startup @@ -254,7 +286,7 @@ Minimize window after unlocking database - Minimizar ventana tras desbloquear base de datos. + Minimizar la ventana tras desbloquear base de datos. Remember previously used databases @@ -262,7 +294,7 @@ recent files - archivos recientes + archivos recientes Load previously open databases on startup @@ -280,25 +312,6 @@ Include beta releases when checking for updates Incluir versiones beta al comprobar actualizaciones - - On database unlock, show entries that - Al desbloquear la base de datos, mostrar apuntes que - - - have expired - On database unlock, show entries that... - ha expirado - - - days - On database unlock, show entries that will expire within %1 days - días - - - will expire within - On database unlock, show entries that... - expirarán en - File Management Gestión de archivos @@ -313,7 +326,7 @@ Automatically save non-data changes when locking database - Guardar automaticamente canbios sin datos al bloquear la base de datos + Guardar automaticamente cambios sin datos al bloquear la base de datos Automatically reload the database when modified externally @@ -323,22 +336,10 @@ Backup database file before saving Hacer una copia de seguridad de la base de datos antes de guardar - - Backup destination - Destino de la copia de seguridad - - - Specifies the database backup file location. Occurrences of "{DB_FILENAME}" are replaced with the filename of the saved database without extension. {TIME:<format>} is replaced with the backup time, see https://doc.qt.io/qt-5/qdatetime.html#toString. <format> defaults to format string "dd_MM_yyyy_hh-mm-ss". - Especifica la localización del archivo de la copia de seguridad de la base de datos. Las ocurrencias de «{DB_FILENAME}» son reemplazadas con el nombre de archivo de la base de datos guardada sin la extensión. {TIME:<format>} es reemplazado con la hora de la copia de seguridad, ver https://doc.qt.io/qt-5/qdatetime.html#toString. <format> su cadena de formato por defecto es «dd_MM_yyyy_hh-mm-ss». - {DB_FILENAME}.old.kdbx {DB_FILENAME}.old.kdbx - - Choose... - Elegir... - Use alternative saving method (may solve problems with Dropbox, Google Drive, GVFS, etc.) Usar método alternativo de guardado (puede resolver problemas con Dropbox, Google Drive, GVFS, etc.) @@ -474,11 +475,11 @@ Auto-Type start delay: - Retardo del inicio del auto-tecleo: + Retardo del inicio de autoescritura: Global Auto-Type shortcut: - Atajo global de autotecleo: + Atajo global de autoescritura: Auto-type start delay milliseconds @@ -491,20 +492,85 @@ Auto-Type typing delay: - Retardo de tecleo del auto-tecleo + Retardo de tecleo de autoescritura Global auto-type shortcut - Atajo global de auto-tecleo + Atajo global de autoescritura Auto-type character typing delay milliseconds - Retardo de auto-tecleo de caracteres + Retardo de autoescritura de caracteres Remember last typed entry for: Recordar último apunte para: + + On database unlock, show entries that will expire within + Al desbloquear la base de datos, mostrar las entradas que caducarán en un plazo de + + + On database unlock, show entries that will expire within + Al desbloquear la base de datos, mostrar las entradas que caducarán en un plazo de + + + days + number of days warning for password expiration + días + + + Destination format: + Formato de destino: + + + <html><head/><body><p><span style=" font-weight:600;">{DB_FILENAME}</span> is replaced with the filename of the saved database without extension</p><p><span style=" font-weight:600;">{TIME:&lt;format&gt;}</span> is replaced with the specified time format (default: dd_MM_yyyy_hh-mm-ss)</p><p>See the User Guide for more details</p></body></html> + <html><head/><body><p><span style=" font-weight:600;">{DB_FILENAME}</span> se sustituye por el nombre de archivo de la base de datos guardada sin extensión</p><p><span style=" font-weight:600;">{TIME:&lt;format&gt;}</span> se sustituye por el formato de hora especificado (por defecto: dd_MM_yyyy_hh-mm-ss)</p><p>Para más información, consulte la Guía del usuario</p></body></html> + + + Choose folder... + Elegir carpeta... + + + Show confirmation before moving entries to recycle bin + Mostrar confirmación antes de mover entradas a papelera + + + Copy data on double clicking field in entry view + Copiar datos al hacer doble clic en un campo de la vista de entrada + + + Show toolbar + Mostrar barra de herramientas + + + Show the menu bar by pressing the Alt key + Mostrar la barra de menús pulsando la tecla Alt + + + Show menubar + Mostrar barra de menú + + + Import settings… + Importar ajustes.... + + + Export settings… + Exportar ajustes... + + + Open browser on double clicking URL field in entry view + Abrir el navegador al hacer doble clic en el campo URL en la vista de entrada + + + Font size: + Tamaño fuente: + + + Font size selection + Selección de tamaño de fuente + ApplicationSettingsWidgetSecurity @@ -514,7 +580,7 @@ Database lock timeout seconds - tiempo de espera de cierre de la base de datos + Tiempo de espera de cierre de la base de datos sec @@ -523,11 +589,11 @@ Clear clipboard after - Purga del portapapeles tras + Purgar el portapapeles tras Clear search query after - Purgar consulta de búsqueda tras + Purgar la consulta de búsqueda tras min @@ -536,7 +602,7 @@ Clipboard clear seconds - Segundos para purgar portapapeles + Segundos para purgar el portapapeles Lock databases after inactivity of @@ -570,18 +636,6 @@ Hide passwords in the entry preview panel Ocultar contraseñas en el apunte del panel de vista previa - - Hide entry notes by default - Ocultar notas del apunte predeterminado - - - Move entries to recycle bin without confirmation - Mover apuntes a la papelera de reciclaje sin confirmación - - - Enable double click to copy the username/password entry columns - Activar pulsación doble para copiar las columnas de apunte de usuario/contraseña - Privacy Privacidad @@ -594,6 +648,18 @@ Hide TOTP in the entry preview panel Ocultar TOTP en el panel de vista previa de apunte + + Lock databases when switching user + Bloquear bases de datos al cambiar de usuario + + + Lock Options + Opciones de bloqueo + + + Hide notes in the entry preview panel + Ocultar notas en el panel de vista previa de apunte + AutoType @@ -607,7 +673,7 @@ Permission Required - Permiso Requerido + Permiso requerido KeePassXC requires the Accessibility permission in order to perform entry level Auto-Type. If you already granted permission, you may have to restart KeePassXC. @@ -641,20 +707,6 @@ Entry does not have attribute for PICKCHARS: %1 El apunte no tiene atributo para PICKCHARS: %1 - - Invalid conversion type: %1 - Tipo de conversión no válido: %1 - - - Invalid conversion syntax: %1 - Sintaxis de conversión no válida: %1 - - - Invalid regular expression syntax %1 -%2 - Sintaxis de expresión regular no válida %1 -%2 - Invalid placeholder: %1 Marcador inválido: %1 @@ -714,7 +766,7 @@ Trying to send invalid keyboard symbol. - + Intentando enviar símbolos de teclado incorrectos. @@ -886,24 +938,25 @@ Seleccione la base de datos correcta para guardar las credenciales. Add to existing entry - + Añadir a apunte existente Existing passkey found. Do you want to register a new passkey for: - + Passkey existente encontrada. +Desea registrar una nueva passkey para: Select the existing passkey and press Update to replace it. - + Seleccione una clave existente y presione Actualiza" para reemplazarla. Authenticate passkey credentials for: - + Autenticar credenciales de passkey de acceso para: Do you want to register a passkey for: - + Desa registrar una passkey para: @@ -988,16 +1041,17 @@ Do you want to delete the entry? Register a new passkey to this entry: - + Añadir una nueva passkey de acceso para esta entrada: KeePassXC - Update passkey - + KeePassXC - Actualizar passkey Entry already has a passkey. Do you want to overwrite the passkey in %1 - %2? - + El apunte ya tiene un passkey. +¿Desea sobreescribirlo con el passkey en %1 - %2? Register @@ -1016,16 +1070,12 @@ Do you want to overwrite the passkey in %1 - %2? Enable browser integration - Activar integración con navegador + Activar integración con navegadores General General - - Browsers installed as snaps are currently not supported. - Los navegadores instalados como snaps no son admitidos. - Enable integration for these browsers: Habilitar integración a estos navegadores: @@ -1117,7 +1167,7 @@ Do you want to overwrite the passkey in %1 - %2? Do not ask permission for HTTP Basic Auth An extra HTTP Basic Auth setting - No solicitar permiso para Autenticación Básica HTTP + No solicitar permiso para Autenticación básica HTTP Automatically creating or updating string fields is not supported. @@ -1129,11 +1179,11 @@ Do you want to overwrite the passkey in %1 - %2? Don't display the popup suggesting migration of legacy KeePassHTTP settings. - No desplegar la ventana emergente sugiriendo migración de parámetros de KeePassHTTP heredados. + No desplegar la ventana emergente sugiriendo migración de configuraciones de KeePassHTTP heredados. Do not prompt for KeePassHTTP settings migration. - No solicitar parámetros de migración de KeePassHTTP. + No solicitar configuraciones de migración de KeePassHTTP. Updates KeePassXC or keepassxc-proxy binary path automatically to native messaging scripts on startup. @@ -1197,18 +1247,6 @@ Do you want to overwrite the passkey in %1 - %2? Custom extension ID ID de extensión personalizado - - Due to Snap sandboxing, you must run a script to enable browser integration.<br />You can obtain this script from %1 - Debido al modo aislado de Snap, debe ejecutar un guion para habilitar la integración con el navegador. Puede obtener este guion desde %1 - - - KeePassXC-Browser is needed for the browser integration to work. <br />Download it for %1 and %2 and %3. %4 - KeePassXC-Browser es necesario para que la integración del navegador funcione.<br />Descárgalo desde %1 y %2 y %3. %4 - - - Please see special instructions for browser extension use below - Vea las instrucciones especiales para el uso de extensión de navegador debajo. - Executable Files Ficheros ejecutables @@ -1251,11 +1289,19 @@ Do you want to overwrite the passkey in %1 - %2? Allows using insecure http://localhost with passkeys for testing purposes. - + Permite usar el iseguro http://localhost con passkeys para propósitos de pruebas. Allow using localhost with passkeys - + Permitir usar localhost con passkeys + + + KeePassXC-Browser is needed for the browser integration to work. <br />Download it for %1 and %2 and %3. + KeePassXC-Browser es necesario para el funcionamiento de la integración con el navegador. Descargalo por %1 y %2 y %3 + + + Browsers installed using Snap or Flatpak are not supported with exception to Firefox installed using Snap. + Los navegadores instalados mediante Snap o Flatpak no son compatibles, a excepción de Firefox instalado mediante Snap. @@ -1399,6 +1445,20 @@ Do you want to overwrite the passkey in %1 - %2? Imported from CSV file: %1 Importar desde archivo CSV: %1 + + No Title Selected + Sin titulo seleccinado + + + No title column was selected, entries will be hard to tell apart. +Are you sure you want to import? + No se ha seleccionado un título para la columna, será difícil asignar los registros correctamente. +¿Desea continuar con la importación? + + + Tags + Etiquetas + CsvParserModel @@ -1462,6 +1522,14 @@ Respaldo de base de datos ubicado en %2 Recycle Bin Papelera + + Database file read error. + Error de lectura del archivo de base de datos. + + + No file path was provided. + No se ha proporcionado ninguna ruta de archivo. + DatabaseOpenDialog @@ -1556,7 +1624,7 @@ To prevent this error from appearing, you must go to "Database Settings / S Desbloqueo de base de datos erróneo y no se introdujo una contraseña. ¿Desea reintentar con una contraseña vacía? -Para prevenir que aparezca este error, debe ir a «Parámetros de base de datos / Seguridad» y restablezca su contraseña. +Para prevenir que aparezca este error, debe ir a «Configuraciones de base de datos / Seguridad» y restablezca su contraseña. Retry with empty password @@ -1572,7 +1640,7 @@ Para prevenir que aparezca este error, debe ir a «Parámetros de base de datos You are using an old key file format which KeePassXC may<br>stop supporting in the future.<br><br>Please consider generating a new key file by going to:<br><strong>Database &gt; Database Security &gt; Change Key File.</strong><br> - Está usando un cerrojo con un formato antiguo que KeePassXC puede<br>dejar de mantener en el futuro.<br><br>Considere generar un cerrojo nuevo yendo a:<br><strong>Base de Datos &gt; Seguridad de Base de Datos &gt; Cambiar Cerrojo.</strong><br> + Está usando un cerrojo con un formato antiguo que KeePassXC puede<br>dejar de mantener en el futuro.<br><br>Considere generar un cerrojo nuevo yendo a:<br><strong>Base de Datos &gt; Seguridad de base de datos &gt; Cambiar cerrojo.</strong><br> Don't show this warning again @@ -1610,14 +1678,6 @@ Para prevenir que aparezca este error, debe ir a «Parámetros de base de datos <p>In addition to a password, you can use a secret file to enhance the security of your database. This file can be generated in your database's security settings.</p><p>This is <strong>not</strong> your *.kdbx database file!</p> <p>Adicionalmente a una contraseña, puede usar un archivo secreto para mejorar la seguridad de su base de datos. Este archivo puede ser generado en sus preferencia de seguridad de base de datos.</p><p>Esto <strong>no</strong> es su archivo de base de datos *.kdbx.</p> - - Click to add a key file. - Clic para añadir un archivo clave. - - - <a href="#" style="text-decoration: underline">I have a key file</a> - <a href="#" style="text-decoration: underline">Tengo un archivo clave</a> - Use hardware key [Serial: %1] Usar clave hardware [Serial: %1] @@ -1654,6 +1714,18 @@ Un archivo de base de datos no es un archivo clave. Refresh Hardware Keys Actualizando claves hardware + + Click to add a key file. + Clic para añadir un archivo clave. + + + <a href="#" style="text-decoration: underline">I have a key file</a> + <a href="#" style="text-decoration: underline">Tengo un archivo clave</a> + + + Hardware keys found, but no slots are configured. + Se han encontrado claves de hardware, pero no se han configurado ranuras. + DatabaseSettingWidgetMetaData @@ -1678,7 +1750,7 @@ Un archivo de base de datos no es un archivo clave. Encryption Settings - Parámetros de cifrado + Configuraciones de cifrado Browser Integration @@ -1688,6 +1760,22 @@ Un archivo de base de datos no es un archivo clave. Maintenance Mantenimiento + + KeeShare + KeeShare + + + Secret Service Integration + Integración con servicio de secretos + + + Remote Sync + Sincronización remota + + + Database Settings: %1 + Configuraciones de la base de datos: 1% + DatabaseSettingsWidgetBrowser @@ -1701,7 +1789,7 @@ Un archivo de base de datos no es un archivo clave. Forget all site-specific settings on entries - Olvidar todos los parámetros del sitio específico en los apuntes + Olvidar todos los configuración del sitio específico en los apuntes Refresh database root group ID @@ -1725,7 +1813,7 @@ Un archivo de base de datos no es un archivo clave. Delete the selected key? - ¿Borro la clave seleccionada? + ¿Eliminar la clave seleccionada? Do you really want to delete the selected key? @@ -1747,7 +1835,7 @@ Esto puede impedir la conexión con el complemento del navegador. Enable Browser Integration to access these settings. - Activar integración del navegador para acceder a estos parámetros. + Activar integración del navegador para acceder a estas configuraciones. Do you really want to disconnect all browsers? @@ -1761,7 +1849,7 @@ Esto puede impedir la conexión con el complemento de navegador. Successfully removed %n encryption key(s) from KeePassXC settings. - Correctamente borrada %n clave de cifrado de la configuración KeePassXC.Correctamente borrada %n claves de cifrado de los parámetros de KeePassXC.Correctamente borrada %n claves de cifrado de los parámetros de KeePassXC. + Correctamente borrada %n clave de cifrado de la configuración KeePassXC.Correctamente borrada %n claves de cifrado de los parámetros de KeePassXC.Correctamente borrada %n claves de cifrado de las configuraciones de KeePassXC. Do you really want forget all site-specific settings on every entry? @@ -1858,14 +1946,14 @@ Are you sure you want to continue without a password? Weak password Contraseña débil - - You must enter a stronger password to protect your database. - Debe introducir una contraseña más fuerte para proteger su base de datos. - This is a weak password! For better protection of your secrets, you should choose a stronger password. ¡Esta es una contraseña débil! Para una mejor protección de sus secretos, debe elegir una contraseña más fuerte. + + The provided password does not meet the minimum quality requirement. + La contraseña entregada no cumple con los requisitos de calidad minimos + DatabaseSettingsWidgetEncryption @@ -1993,7 +2081,7 @@ Si mantiene este número, su base de datos no estará protegida de los ataques p Failed to transform key with new KDF parameters; KDF unchanged. - Error al transformar la clave con nuevos parámetros KDF; KDF sin cambios. + Error al transformar la clave con nuevas configuraciones KDF; KDF sin cambios. MiB @@ -2034,14 +2122,14 @@ Si mantiene este número, su base de datos no estará protegida de los ataques p Enable Secret Service to access these settings. - Active el Servicio Secreto para acceder a estos parámetros. + Active el Servicio Secreto para acceder a estas configuraciones. DatabaseSettingsWidgetGeneral Database Metadata - Metadatos de la Base de Datos + Metadatos de la base de datos Database name: @@ -2069,7 +2157,7 @@ Si mantiene este número, su base de datos no estará protegida de los ataques p History Settings - Parámetros del historial + Configuraciones del historial Maximum number of history items per entry @@ -2089,7 +2177,7 @@ Si mantiene este número, su base de datos no estará protegida de los ataques p Additional Database Settings - Parámetros adicionales de base de datos + Configuraciones adicionales de base de datos Enable compression (recommended) @@ -2167,6 +2255,50 @@ papelera son eliminados de la BdD. Autosave delay since last change checkbox Retardo de autoguardado desde úlimo cambio de caja de seleección + + Public Database Metadata + Metadatos de bases de datos públicas + + + Warning: the following settings are not encrypted. + Advertencia: los siguientes ajustes no están encriptados. + + + Display name: + Mostrar nombre: + + + Publically visible display name used on the unlock dialog + Nombre visible públicamente utilizado en el cuadro de diálogo de desbloqueo + + + Database public display name + Nombre público de la base de datos + + + Display color: + Mostrar color: + + + Publically visible color used on the unlock dialog + Color visible públicamente utilizado en el cuadro de diálogo de desbloqueo + + + Database public display color chooser + Selector de color de la base de datos pública + + + Clear + Limpiar + + + Display icon: + Mostrar icono: + + + Select Database Icon + Seleccionar icono de base de datos + DatabaseSettingsWidgetKeeShare @@ -2228,7 +2360,7 @@ papelera son eliminados de la BdD. Custom Icons Are In Use - Iconos Personalizados En Uso + Iconos personalizados en uso All custom icons are in use by at least one entry or group. @@ -2236,7 +2368,7 @@ papelera son eliminados de la BdD. Purged Unused Icons - Iconos Purgados No Utilizados + Iconos purgados no utilizados Purged %n icon(s) from the database. @@ -2262,6 +2394,139 @@ papelera son eliminados de la BdD. Campo descripción de base de datos + + DatabaseSettingsWidgetRemote + + Sync Commands + Comandos de sincronización + + + Remove + Retirar + + + Command Settings + Configuración de comandos + + + Name + Nombre + + + Save + Guardar + + + Download + Descarga + + + Command: + Comando: + + + Download command field + Fallo en el comando de descarga + + + e.g.: "sftp user@hostname" or "scp user@hostname:DatabaseOnRemote.kdbx {TEMP_DATABASE}" + e.g.: "sftp user@hostname" or "scp user@hostname:DatabaseOnRemote.kdbx {TEMP_DATABASE}" + + + Input: + Entrada: + + + Download input field + Campo de entrada de descarga + + + Upload + Subida + + + Upload command field + Campo de entrada de subida + + + e.g.: "sftp user@hostname" or "scp {TEMP_DATABASE} user@hostname:DatabaseOnRemote.kdbx" + e.g.: "sftp user@hostname" or "scp {TEMP_DATABASE} user@hostname:DatabaseOnRemote.kdbx" + + + Upload input field + Campo de entrada de subida + + + Name cannot be empty. + Nombre no puede ser vacío. + + + Test + Probar + + + Download command cannot be empty. + Comando de descarga no puede ser vacío. + + + Download failed with error: %1 + Descarga falló con el error: %1 + + + Download finished, but file %1 could not be found. + Descarga finalizada, pero el archivo %1 no se puede encontrar. + + + Download successful. + Descarga exitosa. + + + Save Remote Settings + Configuración de guardado remoto + + + You have unsaved changes. Do you want to save them? + Tiene cambios sin guardar. ¿Desea guardarlos? + + + e.g.: +get DatabaseOnRemote.kdbx {TEMP_DATABASE} +exit +--- +{TEMP_DATABASE} is used as placeholder to store the database in a temporary location +The command has to exit. In case of `sftp` as last command `exit` has to be sent + + e.g.: +get DatabaseOnRemote.kdbx {TEMP_DATABASE} +exit +--- +{TEMP_DATABASE} es usado como marcador para guardar la base de datos en una localización temporal +El comando tiene que finalizar. En caso de «sftp» como último comando ha de ser enviado «exit» + + + e.g.: +put {TEMP_DATABASE} DatabaseOnRemote.kdbx +exit +--- +{TEMP_DATABASE} is used as placeholder to store the database in a temporary location +The command has to exit. In case of `sftp` as last command `exit` has to be sent + + e.g.: +put {TEMP_DATABASE} DatabaseOnRemote.kdbx +exit +--- +{TEMP_DATABASE} es usado como marcador para guardar la base de datos en una localización temporal +El comando tiene que finalizar. En caso de «sftp» como último comando ha de ser enviado «exit» + + + Timeout: + Intervalos + + + seconds + segundos + + DatabaseTabWidget @@ -2292,7 +2557,7 @@ Esto es definitivamente un error, por favor infórmeselo a los desarrolladores.< CSV file - Fichero *.csv + Archivo *.csv Merge database @@ -2335,6 +2600,11 @@ Esto es definitivamente un error, por favor infórmeselo a los desarrolladores.< Database tab name modifier %1 [Bloqueada] + + %1 [Temporary] + Database tab name modifier + %1 [Temporal] + DatabaseWidget @@ -2360,11 +2630,11 @@ Esto es definitivamente un error, por favor infórmeselo a los desarrolladores.< Execute command? - ¿Ejecutar instrucción? + ¿Ejecutar comando? Do you really want to execute the following command?<br><br>%1<br> - ¿Desea ejecutar la siguiente instrucción<br><br>%1<br> + ¿Desea ejecutar el siguiente comando?<br><br>%1<br> Remember my choice @@ -2458,25 +2728,6 @@ Save changes? File has changed El archivo ha cambiado - - The database file has changed. Do you want to load the changes? - El archivo de la base de datos ha cambiado. ¿Desea cargar los cambios? - - - Merge Request - Solicitud de combinación - - - The database file has changed and you have unsaved changes. -Do you want to merge your changes? - El archivo de la base de datos ha cambiado y tiene modificaciones sin guardar. ¿Desea combinar sus modificaciones? - - - Could not open the new database file while attempting to autoreload. -Error: %1 - No se pudo abrir el fichero nuevo de base de datos al intentar cargar automáticamente. -Error: %1 - Disable safe saves? ¿Desactivar almacenajes seguros? @@ -2505,7 +2756,7 @@ Disable safe saves and try again? Save database backup - Guardar respaldo de la base de datos + Guardar copia de seguridad de la base de datos Empty recycle bin? @@ -2528,6 +2779,86 @@ Disable safe saves and try again? Database tab name modifier %1 [Nueva base de datos] + + Remote Sync did not contain any download or upload commands. + La sincronización remota no contiene ningún comando de descarga o subida. + + + Remote sync '%1' completed successfully! + ¡Sincronización remota de «%1» completada con éxito! + + + Remote sync '%1' failed: %2 + Fallo de incronización remota «%1»: %2 + + + Error while saving database %1: %2 + Error al guardar base de datos %1: %2 + + + Downloading... + Descargando... + + + Uploading... + Subiendo... + + + Syncing... + Sincronizando... + + + Remove passkey from entry + Eliminar passkey de apunte + + + Do you want to remove the passkey from this entry? + ¿Desea eliminar el passkey de este apunte? + + + The database file "%1" was modified externally + El archivo de base de datos "%1" ha sido modificado externamente + + + Do you want to load the changes? + ¿Quieres cargar los cambios? + + + Reload database + Recargar base de datos + + + Reloading database… + Recargando base de datos... + + + Reload canceled + Recarga cancelada + + + Reload successful + Recarga correcta + + + Reload pending user action… + Recargar acción pendiente del usuario... + + + The database file "%1" was modified externally.<br>How would you like to proceed?<br><br>Merge all changes<br>Ignore the changes on disk until save<br>Discard unsaved changes + El archivo de base de datos "%1" ha sido modificado externamente.<br>¿Cómo le gustaría proceder?<br><br>Combinar todos los cambios<br>Ignorar los cambios en disco hasta guardar<br>Descartar los cambios no guardados + + + The database file "%1" was modified externally.<br>How would you like to proceed?<br><br>Merge all changes then save<br>Overwrite the changes on disk<br>Discard unsaved changes + El archivo de base de datos "%1" ha sido modificado externamente.<br>¿Cómo le gustaría proceder?<br><br>Combinar todos los cambios y guardar<br>Sobrescribir los cambios en el disco<br>Descartar los cambios no guardados + + + Database file overwritten. + archivo de base de datos sobreescrito + + + Database file on disk cannot be unlocked with current credentials.<br>Enter new credentials and/or present hardware key to continue. + El archivo de base de datos en disco no se puede desbloquear con las credenciales actuales.<br>Introduzca nuevas credenciales y/o presente la llave hardware para continuar. + EditEntryWidget @@ -2545,7 +2876,7 @@ Disable safe saves and try again? Auto-Type - Auto-Tecleo + Autoescritura Browser Integration @@ -2557,7 +2888,7 @@ Disable safe saves and try again? Confirm Removal - Confirmar Eliminación + Confirmar eliminación Are you sure you want to remove this URL? @@ -2579,10 +2910,6 @@ Disable safe saves and try again? n/a n/d - - (encrypted) - (cifrado) - Select private key Seleccionar la clave privada @@ -2685,6 +3012,10 @@ Would you like to correct it? %n year(s) %n año%n años%n años + + Failed to decrypt SSH key, ensure password is correct. + Fallo al descifrar clave SSH, asegúrese que la contraseña es correcta. + EditEntryWidgetAdvanced @@ -2781,15 +3112,15 @@ Would you like to correct it? Use custom Auto-Type sequence: - Utilizar secuencia de Auto-Tecleo personalizada: + Utilizar secuencia de autoescritura personalizada: Custom Auto-Type sequence - Secuencia personalizada Auto-Tecleo + Secuencia personalizada de autoescritura Open Auto-Type help webpage - Abrir página de ayuda Auto-Tecleo + Abrir página de ayuda de autoescritura Window Associations @@ -2839,7 +3170,7 @@ Would you like to correct it? Custom Auto-Type sequence for this window - Secuencia personalizada de Auto-Tecleo para esta ventana + Secuencia personalizada de autoescritura para esta ventana @@ -2856,18 +3187,10 @@ Would you like to correct it? Skip Auto-Submit for this entry Descartar autoenvío para este apunte - - Only send this setting to the browser for HTTP Auth dialogs. If enabled, normal login forms will not show this entry for selection. - Solo enviar esta configuración al navegador para los diálogos de autenticación HTTP. Si se habilita, los formularios de autenticación no mostrarán este apunte para su selección. - Use this entry only with HTTP Basic Auth Usar este apunte solo con autenticación básica HTTP - - Do not send this setting to the browser for HTTP Auth dialogs. If enabled, HTTP Auth dialogs will not show this entry for selection. - No enviar esta configuración al navegador para los diálogos de autenticación HTTP. Si se habilita, los formularios de autenticación no mostrarán este apunte para su selección. - Do not use this entry with HTTP Basic Auth No usar este apunte con autenticación básica HTTP @@ -2886,11 +3209,19 @@ Would you like to correct it? These settings affect the entry's behaviour with the browser extension. - + Estas configuraciones afectan al comportamiento de los apuntes con la extensión de naveador. Additional URLs - + URLs adiccionales + + + Only send this entry to the browser for HTTP Auth dialogs. If enabled, normal login forms will not show this entry for selection. + Sólo mandar este registro al navegador para los diálogos de Autenticación HTTP. Si está activo, los formularios de registro normales no mostrarán la selección de este registro. + + + Do not send this entry to the browser for HTTP Auth dialogs. If enabled, HTTP Auth dialogs will not show this entry for selection. + No enviar este registro al navegador para los diálogos de Autenticación HTTP. Si está activo, los diálogos de Autenticación HTTP no mostrarán la selección de este registro. @@ -2956,7 +3287,7 @@ Would you like to correct it? Expiration presets - Parámetros de caducidad + Configuraciones de caducidad Presets @@ -3027,7 +3358,7 @@ Would you like to correct it? Remove key from agent when database is closed/locked - Quitar clave del agente cuando la base de datos está cerrada/bloqueada + Eliminar clave del agente cuando la base de datos está cerrada/bloqueada Comment @@ -3104,16 +3435,20 @@ Would you like to correct it? Remove key from agent after - Quitar clave del agente tras + Eliminar clave del agente tras Remove key from agent after specified seconds - Quitar clave del agente tras los segundos especificados + Eliminar clave del agente tras los segundos especificados seconds segundos + + Clear agent + Vaciar campos + EditGroupWidget @@ -3351,7 +3686,7 @@ Las extensiones mantenidas son: %1. Auto-Type: - Auto-Tecleo: + Autoescritura: Search: @@ -3359,7 +3694,7 @@ Las extensiones mantenidas son: %1. Auto-Type toggle for this and sub groups - Conmutar Auto-Tecleo para éste y subgrupos + Conmutar autoescritura para éste y subgrupos Notes: @@ -3367,7 +3702,7 @@ Las extensiones mantenidas son: %1. Default auto-type sequence field - Campo por defecto de secuencia de Auto-Tecleo + Campo por defecto de secuencia de autoescritura Notes field @@ -3379,7 +3714,7 @@ Las extensiones mantenidas son: %1. Set default Auto-Type sequence - Fijar secuencia de Auto-Tecleo por defecto + Fijar secuencia de autoescritura por defecto Search toggle for this and sub groups @@ -3533,12 +3868,12 @@ Las extensiones mantenidas son: %1. Delete plugin data? - ¿Borro los datos del complemento? + ¿Eliminar los datos del complemento? Do you really want to delete the selected plugin data? This may cause the affected plugins to malfunction. - ¿Desea borrar los datos del complemento seleccionado? + ¿Desea eliminar los datos del complemento seleccionado? Esto puede causar un mal funcionamiento de los complementos afectados. @@ -3556,6 +3891,24 @@ Esto puede causar un mal funcionamiento de los complementos afectados.%1 - Clone %1 - Clonado + + Passkey + Passkey + + + Invalid conversion type: %1 + Tipo de conversión no válido: %1 + + + Invalid conversion syntax: %1 + Sintaxis de conversión no válida: %1 + + + Invalid regular expression syntax %1 +%2 + Sintaxis de expresión regular no válida %1 +%2 + EntryAttachments @@ -3564,6 +3917,21 @@ Esto puede causar un mal funcionamiento de los complementos afectados.No se puede abrir el archivo «%1» + + EntryAttachmentsDialog + + Form + Formulario + + + File name + Nombre de archivo + + + File contents... + Contenido del archivo... + + EntryAttachmentsModel @@ -3595,19 +3963,11 @@ Esto puede causar un mal funcionamiento de los complementos afectados. Remove selected attachment - Quitar adjunto seleccionado + Eliminar adjunto seleccionado Remove - Quitar - - - Rename selected attachment - Renombrar adjunto seleccionado - - - Rename - Renombrar + Eliminar Open selected attachment @@ -3631,11 +3991,11 @@ Esto puede causar un mal funcionamiento de los complementos afectados. Confirm remove - Confirmar quitar + Confirmar eliminar Are you sure you want to remove %n attachment(s)? - ¿Desea eliminar %n dato adjunto?¿Desea eliminar %n datos adjuntos?¿Desea quitar %n datos adjuntos? + ¿Desea eliminar %n dato adjunto?¿Desea eliminar %n datos adjuntos?¿Desea eliminar %n datos adjuntos? Save attachments @@ -3725,6 +4085,18 @@ Would you like to overwrite the existing attachment? El adjunto «%1» ya existe. ¿Desea sobrescribir el adjunto existente? + + New + Nuevo + + + Preview + Vista previa + + + Failed to preview an attachment: Attachment not found + Error al previsualizar un archivo adjunto: Archivo adjunto no encontrado + EntryAttributesModel @@ -3805,7 +4177,7 @@ Would you like to overwrite the existing attachment? Auto-Type - Auto-Tecleo + Autoescritura Tags @@ -3845,7 +4217,7 @@ Would you like to overwrite the existing attachment? Notes - Anotaciones + Notas Expires @@ -3881,7 +4253,7 @@ Would you like to overwrite the existing attachment? Password Strength - Fortaleza de Contraseña + Fortaleza de contraseña Entry notes @@ -3923,6 +4295,10 @@ Would you like to overwrite the existing attachment? Background Color Color del fondo + + Group Path + Ruta de grupo + EntryPreviewWidget @@ -4318,6 +4694,14 @@ Puede habilitar el servicio de iconos del sitio web DuckDuckGo en la sección se Url Url + + Could not load key file. + No se puede leer clave en llavero + + + Could not open remote database. Password or key file may be incorrect. + No se ha podido abrir la base de datos remota. La contraseña o el archivo de claves pueden ser incorrectos. + ImportWizardPageSelect @@ -4421,6 +4805,50 @@ Puede habilitar el servicio de iconos del sitio web DuckDuckGo en la sección se KeePass1 Database Base de datos KeePass1 + + Proton Pass (.json) + Exportación JSON de Proton Pass + + + Proton Pass JSON Export + Exportación JSON de Proton Pass + + + Temporary Database + Base de datos temporal + + + Command: + Comando: + + + e.g.: "sftp user@hostname" or "scp user@hostname:DatabaseOnRemote.kdbx {TEMP_DATABASE}" + e.g.: "sftp user@hostname" or "scp user@hostname:DatabaseOnRemote.kdbx {TEMP_DATABASE}" + + + Input: + Entrada: + + + e.g.: +get DatabaseOnRemote.kdbx {TEMP_DATABASE} +exit +--- +{TEMP_DATABASE} is used as placeholder to store the database in a temporary location +The command has to exit. In case of `sftp` as last commend `exit` has to be sent + + p. ej.: +get DatabaseOnRemote.kdbx {TEMP_DATABASE} +exit +--- +{TEMP_DATABASE} se utiliza como marcador de posición para almacenar la base de datos en una ubicación temporal +El comando tiene que salir. En el caso de `sftp` como último comando `exit` tiene que ser enviado + + + + Remote Database (.kdbx) + Base de datos remota (.kdbx) + KMessageWidget @@ -4532,11 +4960,11 @@ Si ocurre nuevamente entonces su archivo de base de datos puede estar corrupto.< Failed to open buffer for KDF parameters in header - Error al abrir el búfer para los parámetros KDF en la cabecera + Error al abrir el búfer para las configuraciones KDF en la cabecera Unsupported key derivation function (KDF) or invalid parameters - Función de derivación de clave no admitida (KDF) o parámetros no válidos + Función de derivación de clave no admitida (KDF) o configuraciones no válidas Legacy header fields found in KDBX4 file. @@ -4637,7 +5065,7 @@ Si ocurre nuevamente entonces su archivo de base de datos puede estar corrupto.< Failed to serialize KDF parameters variant map Translation comment: variant map = data structure for storing meta data - Ha fallado al serializar parámetros KDF en variante asociada + Ha fallado al serializar configuraciones KDF en variante asociada @@ -5322,19 +5750,19 @@ Are you sure you want to continue with this file? Sa&ve Database As… - Guardar BdD &como... + Guardar base de datos como... Database &Security… - &Seguridad de BdD… + &Seguridad de base de datos… Database &Reports… - Info&rmes de Base de Datos... + Info&rmes de base de datos... &Database Settings… - &Parámetros de base de datos… + &Configuraciones de base de datos… &Clone Entry… @@ -5358,7 +5786,7 @@ Are you sure you want to continue with this file? &Settings - &Parámetros + &Configuraciones &Password Generator @@ -5482,7 +5910,7 @@ Are you sure you want to continue with this file? Remove key from SSH Agent - Quitar clave del agente SSH + Eliminar clave del agente SSH Compact Mode @@ -5506,7 +5934,7 @@ Are you sure you want to continue with this file? Show Menubar - + Mostrar barra del menu Show Toolbar @@ -5561,12 +5989,6 @@ Esta versión no es para uso de producción. Expect some bugs and minor issues, this version is meant for testing purposes. NOTA: Está utilizando una versión preliminar de KeePassXC. Espere algunos defectos y problemas menores, esta versión está destinada para uso en pruebas. - - - WARNING: Your Qt version may cause KeePassXC to crash with an On-Screen Keyboard. -We recommend you use the AppImage available on our downloads page. - ADVERTENCIA: Su versión de Qt puede hacer que KeePassXC se bloquee con un teclado virtual. -Le recomendamos que utilice la AppImage disponible en nuestra página de descargas. No Tags @@ -5640,6 +6062,10 @@ Le recomendamos que utilice la AppImage disponible en nuestra página de descarg Import Passkey Importar passkey + + Remote S&ync… + &Sincronización remota... + Quit Application Salir @@ -5744,6 +6170,10 @@ Le recomendamos que utilice la AppImage disponible en nuestra página de descarg Show Password Generator Mostrar generador de contraseñas + + Remove Passkey From Entry + Eliminar passkey de apunte + Perform Auto-Type: {USERNAME} Realizar escritura automatica: {USERNAME} @@ -5858,7 +6288,7 @@ Le recomendamos que utilice la AppImage disponible en nuestra página de descarg Toggle Show Menubar - + Alternar mostrar barra de herramientas Toggle Show Toolbar @@ -5888,6 +6318,34 @@ Le recomendamos que utilice la AppImage disponible en nuestra página de descarg Toggle Allow Screen Capture Alternar permitir captura de pantalla + + Show Group Panel + Mostrar panel de grupo + + + Toggle Show Group Panel + Alternar Mostrar panel de grupo + + + Setup Remote Sync… + Configurar sincronización remota... + + + Password Generator + Generador de contraseñas + + + E&xpire Entry… + Ca&ducar entrada... + + + Clear SSH Agent + Borrar agente SSH + + + Clear all identities in ssh-agent + Borrar todas las identidades en ssh-agent + ManageDatabase @@ -5998,7 +6456,7 @@ Le recomendamos que utilice la AppImage disponible en nuestra página de descarg Encryption Settings - Parámetros de cifrado + Configuraciones de cifrado Here you can adjust the database encryption settings. Don't worry, you can change them later in the database settings. @@ -6038,6 +6496,25 @@ Le recomendamos que utilice la AppImage disponible en nuestra página de descarg Por favor complete el nombre, y agregue una descripción opcional, para su nueva base de datos: + + NewEntryAttachmentsDialog + + Attachment name cannot be empty + El nombre del archivo adjunto no puede estar vacío + + + Attachment with the same name already exists + Ya existe un archivo adjunto con el mismo nombre + + + Save attachment + Guardar adjunto + + + New entry attachment + Nuevo archivo adjunto de entrada + + NixUtils @@ -6225,6 +6702,10 @@ Le recomendamos que utilice la AppImage disponible en nuestra página de descarg Unexpected EOF when writing private key EOF inesperado al escribir la clave privada + + (encrypted) + (cifrado) + OpenSSHKeyGenDialog @@ -6273,7 +6754,7 @@ Le recomendamos que utilice la AppImage disponible en nuestra página de descarg Export the following passkey entries. - + Exportar los siguientes passkey de apuntes. @@ -6346,15 +6827,15 @@ Do you want to overwrite it? Import the following passkey: - + Importar las siguiete passkey Import the following passkey to this entry: - + Importar los siguientes passkey en este apunte: Default passkeys group (Imported Passkeys) - + Grupo por defecto de passkeys (Passkeys importadas) @@ -6377,25 +6858,27 @@ Do you want to overwrite it? Open passkey file - + Abrir el archivo de passkey Cannot import passkey - + No se pudo importar la passkey Cannot import passkey file "%1". Data is missing. - + No se pudo importar archivo clave «%1». Faltan datos. Cannot import passkey file "%1". The following data is missing: %2 - + No se pudo importar passkey «%1». +Falta los siguientes datos: +%2 Cannot import passkey file "%1". Private key is missing or malformed. - + No se pudo importar archivo passkey «%1». la clave privada esta corrupta o desaparecida @@ -6576,10 +7059,6 @@ The following data is missing: Also choose from: Seleccionar también de: - - Excluded characters: "0", "1", "l", "I", "O", "|", "﹒" - Caracteres excluidos: «0», «1», «l», «I», «O», «|», «﹒» - Exclude look-alike characters Excluir caracteres similares @@ -6604,10 +7083,6 @@ The following data is missing: Word Count: Cantidad de palabras: - - Character Count: - Número de caracteres: - Word Case: Capitalización de palabra: @@ -6620,10 +7095,6 @@ The following data is missing: Add custom wordlist Añadir lista de palabras personalizada - - character - caracter - Close Cerrar @@ -6730,6 +7201,22 @@ Do you want to overwrite it? Special Characters Caracteres especiales + + passwordLength + Longitud de la contraseña + + + Characters: %1 + caracteres: %1 + + + MIXED case + MEZCLAR Mayús/minús + + + Excluded characters: "0", "1", "l", "I", "O", "|", "﹒", "B", "8", "G", "6" + Carácteres excluidos: "0", "1", "l", "I", "O", "|", "﹒", "B", "8", "G", "6" + PasswordWidget @@ -6797,6 +7284,21 @@ Do you want to overwrite it? Pulse la tecla &Tab entre caracteres + + PreviewEntryAttachmentsDialog + + Preview entry attachment + Vista previa del archivo adjunto + + + No preview available + No hay vista previa disponible + + + Image format not supported + Formato de imagen no compatible + + QMessageBox @@ -7475,10 +7977,6 @@ Do you want to overwrite it? Invalid word count %1 Número de palabras inválido %1 - - The word list is too small (< 1000 items) - El listado de palabras es demasiado pequeña (< 1000 elementos) - Title for the entry. Título para el apunte. @@ -7623,10 +8121,6 @@ Do you want to overwrite it? Exit interactive mode. Salir de modo interactivo. - - Format to use when exporting. Available choices are 'xml' or 'csv'. Defaults to 'xml'. - Formato a usar al exportar. Las opciones disponibles son «xml» o «csv». Por defecto «xml». - Exports the content of a database to standard output in the specified format. Exporta el contenido de la base de datos en la salida estándar en el formato especificado. @@ -8215,18 +8709,6 @@ Núcleo: %3 %4 file empty archivo vacío - - malformed string - cadena de caracteres mal formada - - - missing closing quote - comilla de cierre faltante - - - %1: (row, col) %2,%3 - %1: (fila, col) %2,%3 - AES 256-bit AES 256-bit @@ -8470,11 +8952,12 @@ Núcleo: %3 %4 Set the key file for the database. This option is deprecated, use --set-key-file instead. - + Establecer el archivo clave para la base de datos. +Esta opción está obsoleta, use --set-key-file. Databases have been locked. - + Las bases de datos han sido bloqueadas. Attestation not supported @@ -8664,20 +9147,96 @@ This option is deprecated, use --set-key-file instead. Action - Accion + Acción Shortcuts Atajos - Unsupported KDF type, cannot decrypt json file + Unknown passkeys error + Error de passkey desconocido + + + Invalid KDF iterations, cannot decrypt json file + Iteracion KDF invalida, no se pudo desencriptar el archivo json + + + Unsupported format, ensure your Bitwarden export is password-protected + Formato no soportado, asegurate de que tu exportacion Bitwarden esta protegido con contraseña + + + Only PBKDF and Argon2 are supported, cannot decrypt json file + Solo se soportan PBKDF y Argon2, no se uedo desencriptar archivo json + + + Reset Shortcuts + Restablecer atajos + + + Double click an action to change its shortcut + Doble clic a una accion para cambiar el atajo + + + Filter... + Filtrar... + + + Shortcut Conflict + Conflicto de atajos + + + Shortcut %1 conflicts with '%2'. Overwrite shortcut? + Atajo %1 está en conflicto con «%2». ¿Sobreescribir atajo? + + + Cannot generate valid passphrases because the wordlist is too short + No se puede generar una frase de contraseña válida porque la lista de palabras es demasiado corta + + + Encrypted files are not supported. + Los archivos cifrados no son compatibles. + + + Proton Pass Import + Importación de Proton Pass + + + Delete plugin data? + ¿Eliminar los datos del complemento? + + + Delete plugin data from Entry(s)? + ¿Eliminar los datos del complemento del apunte?¿Eliminar los datos del complemento de los apuntes?¿Eliminar los datos del complemento de los apuntes? + + + Passkey + Cerrojo + + + Format to use when exporting. Available choices are 'xml', 'csv' or 'html'. Defaults to 'xml'. + Formato que se utilizará al exportar. Las opciones disponibles son 'xml', 'csv' o 'html'. Por defecto es 'xml'. + + + start minimized to the system tray + iniciar minimizado en la bandeja del sistema + + + malformed string, possible unescaped delimiter - Unknown passkeys error + missing closing delimiter + + %1, row: %2, column: %3 + + + + Tags + Etiquetas + QtIOCompressor @@ -8713,6 +9272,37 @@ This option is deprecated, use --set-key-file instead. Error interno de zlib: + + RemoteHandler + + Command `%1` did not finish in time. Process was killed. + El comando «%1» no ha finalizado en tiempo. El proceso se ha finalizado. + + + Failed to upload merged database. Command `%1` did not finish in time. Process was killed. + Fallo al subir base de datos mezclada. El comando «%1» no ha finalizado en tiempo. El proceso se ha finalizado. + + + Invalid download parameters provided. + Parámetros de descarga inválidos proporcionados. + + + Command `%1` failed to download database. + El comando «%1» falló al descargar base de datos. + + + Invalid database pointer or upload parameters provided. + Puntero de base de datos o parámetros de subida inválidos proporcionados. + + + Command `%1` exited with status code: %2 + El comando «%1» terminó con código de estado: %2 + + + Failed to upload merged database. Command `%1` exited with status code: %2 + Fallo al subir base de datos mezclada. El comando «%1» finalizó con código de estado: %2 + + ReportsWidgetBrowserStatistics @@ -8779,6 +9369,10 @@ This option is deprecated, use --set-key-file instead. Exclude from reports Excluir de los informes + + Expire Entry(s)… + Caducar apunte(s)...Caducar apunte(s)...Caducar entrada(s)... + Only show entries that have a URL Mostrar solo apuntes que tienen una URL @@ -8795,36 +9389,33 @@ This option is deprecated, use --set-key-file instead. (Expired) (Expirado) + + Delete plugin data from Entry(s)… + Eliminando los datos del complemento del apunte...Eliminando los datos del complemento de los apuntes...Eliminando los datos del complemento de los apuntes... + ReportsWidgetHealthcheck - Hover over reason to show additional details. Double-click entries to edit. - Pasar por encima del motivo para mostrar detalles adicionales. Doble clic para editar. + Show expired entries + Mostrar apuntes expirados - Bad - Password quality - Mal + (Expired) + (Expirado) + + + Hover over reason to show additional details. Double-click entries to edit. + Pasar por encima del motivo para mostrar detalles adicionales. Doble clic para editar. Bad — password must be changed Mal — la contraseña debe ser cambiada - - Poor - Password quality - Pobre - Poor — password should be changed Pobre — la contraseña debería ser cambiada - - Weak - Password quality - Débil - Weak — consider changing the password Débil — considere cambiar la contraseña @@ -8873,18 +9464,14 @@ This option is deprecated, use --set-key-file instead. Exclude from reports Excluir de los informes - - Show expired entries - Mostrar apuntes expirados + + Expire Entry(s)… + Caducar apunte(s)...Caducar apunte(s)...Caducar entrada(s)... Show entries that have been excluded from reports Mostrar apuntes que han sido excluidos de los informes - - (Expired) - (Expirado) - ReportsWidgetHibp @@ -8980,6 +9567,10 @@ This option is deprecated, use --set-key-file instead. Exclude from reports Excluir de los informes + + Expire Entry(s)… + Caducar apunte(s)...Caducar apunte(s)...Caducar entrada(s)... + ReportsWidgetPasskeys @@ -9037,15 +9628,15 @@ This option is deprecated, use --set-key-file instead. The passkey file will be vulnerable to theft and unauthorized use, if left unsecured. Are you sure you want to continue? - El archivo de llave va ha estar vunerable a robos y usos no autorizados si lo dejas desprotegido. ¿Estas seguro de que quieres continuar? + El archivo passkey será vunerable a robos y usos no autorizados si lo deja desprotegido. ¿Desea continuar? Please wait, list of entries with passkeys is being updated… - + Espere, la lista de entradas con passkeys está siendo actualizada... No entries with passkeys. - + No hay apuntes con passkeys. @@ -9221,6 +9812,14 @@ This option is deprecated, use --set-key-file instead. No agent running, cannot list identities. No hay ningún agente ejecutándose, no se pueden listar identidades. + + Failed to remove all SSH identities from agent. + Error al eliminar todas las identidades SSH del agente. + + + All SSH identities removed from agent. + Todas las identidades SSH eliminadas del agente. + SearchHelpWidget @@ -9395,11 +9994,11 @@ This option is deprecated, use --set-key-file instead. <html><head/><body><p>This setting does not override disabling recycle bin prompts </p></body></html> - + <html><head/><body><p>Esta configuración no sobreescribe la deshabilitación de indicaciones de la papelera de reciclaje</p></body></html> <html><head/><body><p>This improves compatibility with certain applications which search for password without unlocking the database first.</p><p>But enabling this may also crash the client if the database can not be unlocked within a certain timeout. (Usually 25s, but may be a different value set in applications.) </p></body></html> - + <html><head/><body><p>Esto mejora la compatibilidad con ciertas aplicaciones que buscan constraseñas sin desbloquear la base de datos primero.</p><p>Pero habilitar esto puede también hacer fallar el cliente si la base de datos no puede ser desbloqueda en cierto tiempo. (Usualmente 25s, peoro puede ser un valor diferente en las aplicaciones). </p></body></html> @@ -9506,29 +10105,6 @@ This option is deprecated, use --set-key-file instead. Exportar a %1 - - ShortcutSettingsWidget - - Double click an action to change its shortcut - Doble clic a una accion para cambiar el atajo - - - Shortcut Conflict - Conflicto de atajos - - - Filter... - Filtro... - - - Shortcut %1 conflicts with '%2'. Overwrite shortcut? - Atajo %1 está en conflicto con «%2». ¿Sobreescribir atajo? - - - Reset Shortcuts - Resetear atajos - - TagModel @@ -9817,14 +10393,18 @@ Ejemplo: JBSWY3DPEHPK3PXP No hardware keys detected No se detectaron claves hardware - - <p>If you own a <a href="https://www.yubico.com/">YubiKey</a> or <a href="https://onlykey.io">OnlyKey</a>, you can use it for additional security.</p><p>The key requires one of its slots to be programmed as <a href="https://docs.yubico.com/yesdk/users-manual/application-otp/challenge-response.html">HMAC-SHA1 Challenge-Response</a>.</p> - <p>Si posee una <a href="https://www.yubico.com/">YubiKey</a> o <a href="https://onlykey.io">OnlyKey</a>, puede usarla para seguridad adicional.</p><p>La clave requiere que una de sus ranuras sea programada como <a href="https://docs.yubico.com/yesdk/users-manual/application-otp/challenge-response.html">HMAC-SHA1 Challenge-Response</a>.</p> - Refresh hardware keys Actualizar claves hardware + + <p>If you own a <a href="https://www.yubico.com/">YubiKey</a> or <a href="https://onlykey.io">OnlyKey</a>, you can use it for additional security.</p><p>The key requires one of its slots to be programmed with <a href="https://keepassxc.org/docs/#faq-yubikey-howto">Challenge-Response</a>.</p> + <p>Si posee un <a href="https://www.yubico.com/">YubiKey</a> o <a href="https://onlykey.io">OnlyKey</a>, puede utilizarlo para mayor seguridad.</p><p>La llave requiere que una de sus ranuras esté programada con <a href="https://keepassxc.org/docs/#faq-yubikey-howto">Challenge-Response</a>.</p> + + + Hardware keys found, but no slots are configured + Se han encontrado llaves hardware, pero no hay ranuras configuradas + YubiKeyInterfacePCSC diff --git a/share/translations/keepassxc_et.ts b/share/translations/keepassxc_et.ts index b9e7bf34a..6628d47cc 100644 --- a/share/translations/keepassxc_et.ts +++ b/share/translations/keepassxc_et.ts @@ -217,18 +217,50 @@ You must restart the application to set the new language. Would you like to restart now? Keele vahetamiseks tuleb KeePassXC uuesti käivitada. Kas teha seda kohe? - - Reset Settings? - Seadete lähtestamise kinnitus - - - Are you sure you want to reset all general and security settings to default? - Kas oled kindel, et tahad kõik üld- ja turvaseaded lähtestada? - Select backup storage directory Varundamise sihtkataloogi valimine + + Confirm Reset + Lähtestamise kinnitus + + + Are you sure you want to reset all settings to default? + Kas oled kindel, et tahad kõik seaded lähtestada? + + + Import KeePassXC Settings + KeePassXC seadete importimine + + + Failed to import settings from %1, not a valid settings file. + Failist „%1” seadete importimine ei õnnestunud, tegemist pole korrektse seadete failiga. + + + Export KeePassXC Settings + KeePassXC seadete eksportimine + + + Small + väike + + + Normal + tavaline + + + Medium + keskmine + + + Large + suur + + + Custom + kohandatud + ApplicationSettingsWidgetGeneral @@ -280,25 +312,6 @@ Include beta releases when checking for updates Sobivad ka beetaversioonid - - On database unlock, show entries that - Andmebaasi avamisel näidatakse kirjeid, mis - - - have expired - On database unlock, show entries that... - on aegunud - - - days - On database unlock, show entries that will expire within %1 days - päeva jooksul - - - will expire within - On database unlock, show entries that... - aeguvad - File Management Failihaldus @@ -323,22 +336,10 @@ Backup database file before saving Enne salvestamist tehakse andmebaasifailist varukoopia - - Backup destination - Varundamise sihtkoht: - - - Specifies the database backup file location. Occurrences of "{DB_FILENAME}" are replaced with the filename of the saved database without extension. {TIME:<format>} is replaced with the backup time, see https://doc.qt.io/qt-5/qdatetime.html#toString. <format> defaults to format string "dd_MM_yyyy_hh-mm-ss". - Määrab andmebaasi varukoopia salvestuskoha. „{DB_FILENAME}” asendatakse salvestatud andmebaasi failinimega (ilma laiendita). {TIME:<vorming>} asendatakse varundamisajaga, vaata https://doc.qt.io/qt-5/qdatetime.html#toString. Vaikimisi on <vorming> „dd_MM_yyyy_hh-mm-ss” (s.t nt 15_04_2022_13-25-46). - {DB_FILENAME}.old.kdbx {DB_FILENAME}.vana.kdbx - - Choose... - Vali... - Use alternative saving method (may solve problems with Dropbox, Google Drive, GVFS, etc.) Alternatiivse salvestusmeetodi kasutamine (võib lahendada probleemid Dropboxi, Google Drive’i, GVFS-i jms-ga) @@ -505,6 +506,71 @@ Remember last typed entry for: Viimati sisestatud kirjet mäletatakse: + + On database unlock, show entries that will expire within + Andmebaasi avamisel näidatakse kirjeid, mis aeguvad + + + On database unlock, show entries that will expire within + Andmebaasi avamisel näidatakse kirjeid, mis aeguvad + + + days + number of days warning for password expiration + päeva jooksul + + + Destination format: + Sihtfaili nimevorming: + + + <html><head/><body><p><span style=" font-weight:600;">{DB_FILENAME}</span> is replaced with the filename of the saved database without extension</p><p><span style=" font-weight:600;">{TIME:&lt;format&gt;}</span> is replaced with the specified time format (default: dd_MM_yyyy_hh-mm-ss)</p><p>See the User Guide for more details</p></body></html> + <html><head/><body><p><span style=" font-weight:600;">{DB_FILENAME}</span> tähistab salvestatud andmebaasi failinime ilma laiendita.</p><p><span style=" font-weight:600;">{TIME:&lt;vorming&gt;}</span> tähistab määratud vormingus ajaväärtust (vaikimisi: dd_MM_yyyy_hh-mm-ss).</p><p>Lisateavet leiad käsiraamatust.</p></body></html> + + + Choose folder... + Vali kaust… + + + Show confirmation before moving entries to recycle bin + Kirjete prügikasti viskamisel küsitakse kinnitust + + + Copy data on double clicking field in entry view + Kirjevaates kopeerib topeltklõps väljal selle sisu lõikepuhvrisse + + + Show toolbar + Tööriistariba nähtaval + + + Show the menu bar by pressing the Alt key + Peidetud menüüriba puhul saab menüü avada Alt-klahviga + + + Show menubar + Menüüriba nähtaval + + + Import settings… + Impordi seaded… + + + Export settings… + Ekspordi seaded… + + + Open browser on double clicking URL field in entry view + Kirjevaates avab topeltklõps URL-il selle brauseris + + + Font size: + Fondi suurus: + + + Font size selection + Fondisuuruse valik + ApplicationSettingsWidgetSecurity @@ -570,18 +636,6 @@ Hide passwords in the entry preview panel Kirjete eelvaatepaneelil varjatakse paroolid täppidega - - Hide entry notes by default - Vaikimisi peidetakse kirjete märkmed - - - Move entries to recycle bin without confirmation - Kirjete prügikasti viskamisel kinnitust ei küsita - - - Enable double click to copy the username/password entry columns - Topeltklõps kasutajanime/parooli veerus kopeerib selle lõikepuhvrisse - Privacy Privaatsus @@ -594,6 +648,18 @@ Hide TOTP in the entry preview panel Kirjete eelvaatepaneelil varjatakse TOTP kood + + Lock databases when switching user + Andmebaasid lukustatakse kasutaja vahetamisel + + + Lock Options + Lukustamise seaded + + + Hide notes in the entry preview panel + Kirjete eelvaatepaneelil varjatakse märkmed + AutoType @@ -641,20 +707,6 @@ Entry does not have attribute for PICKCHARS: %1 PICKCHARS-automaatsisestuseks määratud atribuuti „%1” kirjes ei leidu. - - Invalid conversion type: %1 - Vigane teisendustüüp: %1 - - - Invalid conversion syntax: %1 - Vigane teisendussüntaks: %1 - - - Invalid regular expression syntax %1 -%2 - Vigane regulaaravaldise süntaks %1 -%2 - Invalid placeholder: %1 Vigane kohahoidja: %1 @@ -714,7 +766,7 @@ Trying to send invalid keyboard symbol. - + Prooviti saata vigast klahvisümbolit. @@ -886,24 +938,25 @@ Vali, millisesse neist tunnused salvestada tuleks. Add to existing entry - + Lisa olemasolevale kirjele Existing passkey found. Do you want to register a new passkey for: - + Leiti olemasolev pääsuvõti. +Vali kirje, millele uus pääsuvõti registreerida: Select the existing passkey and press Update to replace it. - + Vali olemasolev pääsuvõti ja klõpsa selle asendamiseks „Uuenda”. Authenticate passkey credentials for: - + Pääsuvõtme tunnuste autentimine: Do you want to register a passkey for: - + Kirje, millele uus pääsuvõti registreerida: @@ -988,16 +1041,17 @@ Kas lubad selle kirje kustutada? Register a new passkey to this entry: - + Registreeri uus pääsuvõti sellesse kirjesse: KeePassXC - Update passkey - + Pääsuvõtme uuendamine – KeePassXC Entry already has a passkey. Do you want to overwrite the passkey in %1 - %2? - + Kirjel „%1” on juba pääsuvõti. +Kas soovid selle uue pääsuvõtmega (%2) üle kirjutada? Register @@ -1022,10 +1076,6 @@ Do you want to overwrite the passkey in %1 - %2? General Üldine - - Browsers installed as snaps are currently not supported. - <i>Snap</i>’ina paigaldatud brausereid praegu ei toetata. - Enable integration for these browsers: Lubatakse lõimimine järgmiste brauseritega: @@ -1197,18 +1247,6 @@ Do you want to overwrite the passkey in %1 - %2? Custom extension ID Kohandatud laienduse-ID - - Due to Snap sandboxing, you must run a script to enable browser integration.<br />You can obtain this script from %1 - <i>Snap</i>’ide isoleerituse tõttu tuleb brauserilõimingu võimaldamiseks esmalt teatud skript käivitada.<br />Vajaliku skripti saab aadressilt %1. - - - KeePassXC-Browser is needed for the browser integration to work. <br />Download it for %1 and %2 and %3. %4 - Lõimingu toimimiseks peab brauserile olema paigaldatud laiendus KeePassXC-Browser. <br />See on saadaval %1i, %2’i ja %3’i jaoks. %4 - - - Please see special instructions for browser extension use below - Vaata allpool brauserilaienduse kasutamise erijuhiseid. - Executable Files Rakendusfailid @@ -1251,11 +1289,19 @@ Do you want to overwrite the passkey in %1 - %2? Allows using insecure http://localhost with passkeys for testing purposes. - + Märkimisel lubatakse pääsuvõtmete testimiseks kasutada ebaturvalist aadressi http://localhost. Allow using localhost with passkeys - + Lubatakse localhosti kasutamine pääsuvõtmetega + + + KeePassXC-Browser is needed for the browser integration to work. <br />Download it for %1 and %2 and %3. + Lõimingu toimimiseks peab brauserile olema paigaldatud laiendus KeePassXC-Browser. <br />See on saadaval %1i, %2’i ja %3’i jaoks. + + + Browsers installed using Snap or Flatpak are not supported with exception to Firefox installed using Snap. + Kui paigaldatud veebibrauser on pakendatud Snapina või Flatpakina, siis KeepassXC tugi puudub, välja arvatud Snapina paigaldatud Firefoxi puhul. @@ -1399,6 +1445,20 @@ Do you want to overwrite the passkey in %1 - %2? Imported from CSV file: %1 Imporditud CSV-failist: %1 + + No Title Selected + Pealkirja pole valitud + + + No title column was selected, entries will be hard to tell apart. +Are you sure you want to import? + Pealkirjaveergu ei määratud, seega saab olema raske kirjeid eristada. +Kas oled kindel, et soovid importida? + + + Tags + Sildid + CsvParserModel @@ -1462,6 +1522,14 @@ Varuandmebaasi asukoht: %2 Recycle Bin Prügikast + + Database file read error. + Viga andmebaasifaili lugemisel. + + + No file path was provided. + Faili askukohta ei antud. + DatabaseOpenDialog @@ -1610,14 +1678,6 @@ Selle veateate ilmumise vältimiseks peaksid avama andmebaasi seadetes turvalisu <p>In addition to a password, you can use a secret file to enhance the security of your database. This file can be generated in your database's security settings.</p><p>This is <strong>not</strong> your *.kdbx database file!</p> <p>Lisaks paroolile saab andmebaasi turvalisuse suurendamiseks kasutada võtmefaili. Selle saab genereerida andmebaasi turvaseadetes.</p><p>See <strong>ei ole</strong> sinu *.kdbx andmebaasifail!</p> - - Click to add a key file. - Klõpsa võtmefaili lisamiseks. - - - <a href="#" style="text-decoration: underline">I have a key file</a> - <a href="#" style="text-decoration: underline">Mul on võtmefail</a> - Use hardware key [Serial: %1] Riistvaralise võtme kasutamine (seerianumber: %1) @@ -1654,6 +1714,18 @@ Kas oled kindel, et soovid selle failiga jätkata? Refresh Hardware Keys Värskenda riistvaraliste võtmete loendit + + Click to add a key file. + Klõpsa võtmefaili lisamiseks. + + + <a href="#" style="text-decoration: underline">I have a key file</a> + <a href="#" style="text-decoration: underline">Mul on võtmefail</a> + + + Hardware keys found, but no slots are configured. + Leiti riistvaraline võti, kuid ühtki pesa pole seadistatud. + DatabaseSettingWidgetMetaData @@ -1688,6 +1760,22 @@ Kas oled kindel, et soovid selle failiga jätkata? Maintenance Hooldus + + KeeShare + KeeShare + + + Secret Service Integration + Saladuste teenuse lõiming + + + Remote Sync + Sünkimine + + + Database Settings: %1 + Andmebaasi seaded: %1 + DatabaseSettingsWidgetBrowser @@ -1858,14 +1946,14 @@ Kas oled kindel, et soovid jätkata ilma paroolita? Weak password Nõrk parool - - You must enter a stronger password to protect your database. - Andmebaasi kaitsmiseks tuleb kasutada tugevamat parooli. - This is a weak password! For better protection of your secrets, you should choose a stronger password. See on liiga nõrk parool! Oma saladuste paremaks kaitsmiseks peaksid valima tugevama parooli. + + The provided password does not meet the minimum quality requirement. + Sisestatud parool ei vasta kvaliteedinõuetele. + DatabaseSettingsWidgetEncryption @@ -2167,6 +2255,50 @@ eemaldatakse kirje andmebaasist. Autosave delay since last change checkbox Automaatsalvestusega viivitamise märkeruut + + Public Database Metadata + Andmebaasi avalikud metaandmed + + + Warning: the following settings are not encrypted. + <b>Hoiatus:</b> need seaded pole krüptitud. + + + Display name: + Kuvatav nimi: + + + Publically visible display name used on the unlock dialog + Luku avamise dialoogis näidatav nimi + + + Database public display name + Andmebaasi avalikult kuvatav nimi + + + Display color: + Kuvatav värv: + + + Publically visible color used on the unlock dialog + Luku avamise dialoogis näidatav värv + + + Database public display color chooser + Andmebaasi avalikult kuvatava värvi valimine + + + Clear + Puhasta + + + Display icon: + Kuvatav ikoon: + + + Select Database Icon + Andmebaasi ikooni valimine + DatabaseSettingsWidgetKeeShare @@ -2262,6 +2394,141 @@ eemaldatakse kirje andmebaasist. Andmebaasi kirjelduse väli + + DatabaseSettingsWidgetRemote + + Sync Commands + Sünkimiskäsud + + + Remove + Eemalda + + + Command Settings + Käsuseaded + + + Name + Nimi + + + Save + Salvesta + + + Download + Allalaadimine + + + Command: + Käsk: + + + Download command field + Allalaadimiskäsu väli + + + e.g.: "sftp user@hostname" or "scp user@hostname:DatabaseOnRemote.kdbx {TEMP_DATABASE}" + nt „sftp kasutaja@masinanimi” või „scp kasutaja@masinanimi:Andmebaas_kaugarvutis.kdbx {TEMP_DATABASE}” + + + Input: + Sisend: + + + Download input field + Allalaadimise sisendiväli + + + Upload + Üleslaadimine + + + Upload command field + Üleslaadimiskäsu väli + + + e.g.: "sftp user@hostname" or "scp {TEMP_DATABASE} user@hostname:DatabaseOnRemote.kdbx" + nt „sftp kasutaja@masinanimi” või „scp {TEMP_DATABASE} kasutaja@masinanimi:Andmebaas_kaugarvutis.kdbx” + + + Upload input field + Üleslaadimise sisendiväli + + + Name cannot be empty. + Nimi ei saa olla tühi. + + + Test + Testi + + + Download command cannot be empty. + Allalaadimiskäsk ei saa olla tühi. + + + Download failed with error: %1 + Allalaadimine ebaõnnestus, veateade: %1 + + + Download finished, but file %1 could not be found. + Allalaadimine lõpetati, aga faili „%1” ei leitud. + + + Download successful. + Allalaadimine valmis. + + + Save Remote Settings + Salvesta sünkimisseadistus + + + You have unsaved changes. Do you want to save them? + Sul on salvestamata muudatusi. Kas tahad need salvestada? + + + e.g.: +get DatabaseOnRemote.kdbx {TEMP_DATABASE} +exit +--- +{TEMP_DATABASE} is used as placeholder to store the database in a temporary location +The command has to exit. In case of `sftp` as last command `exit` has to be sent + + nt: +get Andmebaas_kaugarvutis.kdbx {TEMP_DATABASE} +exit +--- +{TEMP_DATABASE} on kohahoidja, mis tähistab ajutisse asukohta salvestatud andmebaasi. +Käsk peab oma töö lõpetama, nt „sftp” puhul peab viimane saadetav käsk olema „exit”. + + + + e.g.: +put {TEMP_DATABASE} DatabaseOnRemote.kdbx +exit +--- +{TEMP_DATABASE} is used as placeholder to store the database in a temporary location +The command has to exit. In case of `sftp` as last command `exit` has to be sent + + nt: +put {TEMP_DATABASE} Andmebaas_kaugarvutis.kdbx +exit +--- +{TEMP_DATABASE} on kohahoidja, mis tähistab ajutisse asukohta salvestatud andmebaasi. +Käsk peab oma töö lõpetama, nt „sftp” puhul peab viimane saadetav käsk olema „exit”. + + + + Timeout: + Ajalimiit: + + + seconds + sekundit + + DatabaseTabWidget @@ -2335,6 +2602,11 @@ See on kahtlemata programmiviga – palun anna sellest arendajatele teada!Database tab name modifier %1 [lukus] + + %1 [Temporary] + Database tab name modifier + %1 [ajutine] + DatabaseWidget @@ -2458,26 +2730,6 @@ Kas salvestada muudatused? File has changed Faili on muudetud - - The database file has changed. Do you want to load the changes? - Andmebaasifaili on muudetud. Kas tahad selle uuesti avada? - - - Merge Request - Mestimistaotlus - - - The database file has changed and you have unsaved changes. -Do you want to merge your changes? - Andmebaasifaili on muudetud, aga sinul on salvestamata muudatusi. -Kas tahad oma muudatused mestida? - - - Could not open the new database file while attempting to autoreload. -Error: %1 - Automaatse taaslaadimise käigus polnud uut andmebaasifaili võimalik avada. -Veateade: %1 - Disable safe saves? Turvalise salvestamise keelamine @@ -2529,6 +2781,86 @@ Kas keelata turvaline salvestamine ja proovida seejärel uuesti? Database tab name modifier %1 [uus andmebaas] + + Remote Sync did not contain any download or upload commands. + Sünkimisseadistus ei sisalda alla- ega üleslaadimiskäske. + + + Remote sync '%1' completed successfully! + Sünkimine „%1” kenasti lõpetatud! + + + Remote sync '%1' failed: %2 + Sünkimine „%1” ebaõnnestus: %2 + + + Error while saving database %1: %2 + Andmebaasi „%1” salvestamisel tekkis tõrge: %2 + + + Downloading... + Allalaadimine... + + + Uploading... + Üleslaadimine... + + + Syncing... + Sünkimine... + + + Remove passkey from entry + Kirjelt pääsuvõtme eemaldamine + + + Do you want to remove the passkey from this entry? + Kas soovid sellelt kirjelt pääsuvõtme eemaldada? + + + The database file "%1" was modified externally + Andmebaasifaili „%1” on väljastpoolt muudetud + + + Do you want to load the changes? + Kas tahad muudatused laadida? + + + Reload database + Laadi andmebaas uuesti + + + Reloading database… + Andmebaasi uuestilaadimine… + + + Reload canceled + Uuestilaadimine tühistati + + + Reload successful + Uuestilaadimine valmis + + + Reload pending user action… + Uuestilaadimine ootab kasutaja tegevust… + + + The database file "%1" was modified externally.<br>How would you like to proceed?<br><br>Merge all changes<br>Ignore the changes on disk until save<br>Discard unsaved changes + Andmebaasifaili „%1” on väljastpoolt muudetud.<br>Kuidas soovid jätkata?<br><br>Mesti kõik muudatused<br>Eira muudatusi kuni salvestamiseni<br>Loobu salvestamata muudatustest + + + The database file "%1" was modified externally.<br>How would you like to proceed?<br><br>Merge all changes then save<br>Overwrite the changes on disk<br>Discard unsaved changes + Andmebaasifaili „%1” on väljastpoolt muudetud.<br>Kuidas soovid jätkata?<br><br>Mesti kõik muudatused ja seejärel salvesta andmebaas<br>Kirjuta muudetud fail üle<br>Loobu salvestamata muudatustest + + + Database file overwritten. + Andmebaasifail ülekirjutatud. + + + Database file on disk cannot be unlocked with current credentials.<br>Enter new credentials and/or present hardware key to continue. + Praegu kehtivate tunnustega ei õnnestunud andmebaasifaili lukku avada.<br>Jätkamiseks sisesta uued tunnused ja/või ühenda riistvaraline võti. + EditEntryWidget @@ -2580,10 +2912,6 @@ Kas keelata turvaline salvestamine ja proovida seejärel uuesti? n/a - - (encrypted) - (krüptitud) - Select private key Privaatvõtme valimine @@ -2686,6 +3014,10 @@ Kas soovid vea parandada? %n year(s) %n aasta pärast%n aasta pärast + + Failed to decrypt SSH key, ensure password is correct. + SSH-võtme lahtikrüptimine ebaõnnestus. Vaata, et parool oleks õige. + EditEntryWidgetAdvanced @@ -2859,18 +3191,10 @@ isegi kui see ei vasta kvaliteedinõuetele. Märgi see ruut, kui parooli keeruku Skip Auto-Submit for this entry Automaatsisestus jäetakse selle kirje puhul vahele - - Only send this setting to the browser for HTTP Auth dialogs. If enabled, normal login forms will not show this entry for selection. - Märkimisel saadetakse see kirje brauserile ainult HTTP autentimisdialoogide puhul ning tavaliste sisselogimisvormide korral seda kirjet valida ei saa. - Use this entry only with HTTP Basic Auth Seda kirjet kasutatakse vaid HTTP lihtautentimisel - - Do not send this setting to the browser for HTTP Auth dialogs. If enabled, HTTP Auth dialogs will not show this entry for selection. - Märkimisel seda kirjet HTTP autentimisdialoogide puhul brauserile ei saadeta ning HTTP autentimisdialoogides seda kirjet valida ei saa. - Do not use this entry with HTTP Basic Auth Seda kirjet HTTP lihtautentimisel ei kasutata @@ -2889,11 +3213,19 @@ isegi kui see ei vasta kvaliteedinõuetele. Märgi see ruut, kui parooli keeruku These settings affect the entry's behaviour with the browser extension. - + Need seaded mõjutavad kirje käitumist brauserilaiendusega. Additional URLs - + Lisa-URL-id + + + Only send this entry to the browser for HTTP Auth dialogs. If enabled, normal login forms will not show this entry for selection. + Märkimisel saadetakse see kirje brauserile ainult HTTP autentimisdialoogide puhul ning tavaliste sisselogimisvormide korral seda kirjet valida ei saa. + + + Do not send this entry to the browser for HTTP Auth dialogs. If enabled, HTTP Auth dialogs will not show this entry for selection. + Märkimisel seda kirjet HTTP autentimisdialoogide puhul brauserile ei saadeta ning HTTP autentimisdialoogides seda kirjet valida ei saa. @@ -3117,6 +3449,10 @@ isegi kui see ei vasta kvaliteedinõuetele. Märgi see ruut, kui parooli keeruku seconds sekundit + + Clear agent + Tühjenda agent + EditGroupWidget @@ -3272,7 +3608,7 @@ isegi kui see ei vasta kvaliteedinõuetele. Märgi see ruut, kui parooli keeruku Synchronize - sünkroonimine + sünkimine Your KeePassXC version does not support sharing this container type. @@ -3559,6 +3895,24 @@ See võib põhjustada asjaomaste pluginate töös tõrkeid. %1 - Clone %1 – koopia + + Passkey + Pääsuvõti + + + Invalid conversion type: %1 + Vigane teisendustüüp: %1 + + + Invalid conversion syntax: %1 + Vigane teisendussüntaks: %1 + + + Invalid regular expression syntax %1 +%2 + Vigane regulaaravaldise süntaks %1 +%2 + EntryAttachments @@ -3567,6 +3921,21 @@ See võib põhjustada asjaomaste pluginate töös tõrkeid. Faili „%1” avamine pole võimalik + + EntryAttachmentsDialog + + Form + Vorm + + + File name + Faili nimi + + + File contents... + Faili sisu… + + EntryAttachmentsModel @@ -3604,14 +3973,6 @@ See võib põhjustada asjaomaste pluginate töös tõrkeid. Remove Eemalda - - Rename selected attachment - Muuda valitud kaasatud faili nime - - - Rename - Muuda nime - Open selected attachment Ava valitud kaasatud fail @@ -3727,6 +4088,18 @@ Would you like to overwrite the existing attachment? Kaasatud fail nimega „%1” on juba olemas. Kas soovid selle faili uuega üle kirjutada? + + New + Uus + + + Preview + Eelvaade + + + Failed to preview an attachment: Attachment not found + Kaasatud faili eelvaate loomine ebaõnnestus: kaasatud faili ei leitud + EntryAttributesModel @@ -3925,6 +4298,10 @@ Kas soovid selle faili uuega üle kirjutada? Background Color Taustavärv + + Group Path + Grupi asukoht + EntryPreviewWidget @@ -4319,6 +4696,14 @@ You can enable the DuckDuckGo website icon service in the security section of th Url URL + + Could not load key file. + Võtmefaili ei õnnestunud laadida. + + + Could not open remote database. Password or key file may be incorrect. + Võrguandmebaasi ei õnnestunud avada. Küllap oli parool või võtmefail vale. + ImportWizardPageSelect @@ -4422,6 +4807,50 @@ You can enable the DuckDuckGo website icon service in the security section of th KeePass1 Database KeePass 1 andmebaas + + Proton Pass (.json) + Proton Pass (.json) + + + Proton Pass JSON Export + Proton Passi JSON-eksport + + + Temporary Database + Ajutisse andmebaasi + + + Command: + Käsk: + + + e.g.: "sftp user@hostname" or "scp user@hostname:DatabaseOnRemote.kdbx {TEMP_DATABASE}" + nt „sftp kasutaja@masinanimi” või „scp kasutaja@masinanimi:Andmebaas_kaugarvutis.kdbx {TEMP_DATABASE}” + + + Input: + Sisend: + + + e.g.: +get DatabaseOnRemote.kdbx {TEMP_DATABASE} +exit +--- +{TEMP_DATABASE} is used as placeholder to store the database in a temporary location +The command has to exit. In case of `sftp` as last commend `exit` has to be sent + + nt: +get Andmebaas_kaugarvutis.kdbx {TEMP_DATABASE} +exit +--- +{TEMP_DATABASE} on kohahoidja, mis tähistab ajutisse asukohta salvestatud andmebaasi. +Käsk peab oma töö lõpetama, nt „sftp” puhul peab viimane saadetav käsk olema „exit”. + + + + Remote Database (.kdbx) + Andmebaas võrgus (.kdbx) + KMessageWidget @@ -5035,7 +5464,7 @@ Kui probleem püsib, võib andmebaasifail olla rikutud. Synchronized with %1 - Sünkroonitud asukohaga „%1” + Süngitud asukohaga „%1” Import is disabled in settings @@ -5059,7 +5488,7 @@ Kui probleem püsib, võib andmebaasifail olla rikutud. Synchronized with - Sünkroonitud asukohaga + Süngitud asukohaga @@ -5507,7 +5936,7 @@ Kas oled kindel, et soovid selle failiga jätkata? Show Menubar - + &Menüüriba nähtaval Show Toolbar @@ -5563,12 +5992,6 @@ See versioon ei ole mõeldud töökeskkonnas kasutamiseks. Expect some bugs and minor issues, this version is meant for testing purposes. NB: kasutad KeePassXC testversiooni. Eeldatavasti leidub selles programmivigu ja muid väiksemaid hädasid – see versioon on mõeldud testimiseks, mitte töökeskkonnas kasutamiseks. - - - WARNING: Your Qt version may cause KeePassXC to crash with an On-Screen Keyboard. -We recommend you use the AppImage available on our downloads page. - HOIATUS: sinu Qt versioon võib põhjustada KeePassXC kokkujooksmist ekraaniklaviatuuri kasutamisel. -Võiksid kaaluda KeePassXC allalaadimislehel oleva AppImage’i kasutamist. No Tags @@ -5642,6 +6065,10 @@ Võiksid kaaluda KeePassXC allalaadimislehel oleva AppImage’i kasutamist.Import Passkey Impordi pääsuvõti + + Remote S&ync… + Sünkimine... + Quit Application Välju rakendusest @@ -5746,6 +6173,10 @@ Võiksid kaaluda KeePassXC allalaadimislehel oleva AppImage’i kasutamist.Show Password Generator Kuva parooligeneraator + + Remove Passkey From Entry + Eemalda kirjelt pääsuvõti + Perform Auto-Type: {USERNAME} Soorita automaatsisestus: {USERNAME} @@ -5860,7 +6291,7 @@ Võiksid kaaluda KeePassXC allalaadimislehel oleva AppImage’i kasutamist. Toggle Show Menubar - + Lülita menüüriba nähtavust Toggle Show Toolbar @@ -5890,6 +6321,34 @@ Võiksid kaaluda KeePassXC allalaadimislehel oleva AppImage’i kasutamist.Toggle Allow Screen Capture Lülita akna pildistamise lubamist + + Show Group Panel + Gruppide paneel nähtaval + + + Toggle Show Group Panel + Lülita gruppide paneeli nähtavust + + + Setup Remote Sync… + Seadista sünkimine... + + + Password Generator + Parooligeneraator + + + E&xpire Entry… + Märgi kirje &aegunuks… + + + Clear SSH Agent + Tühjenda SSH agent + + + Clear all identities in ssh-agent + Eemalda SSH agendilt kõik identiteedid + ManageDatabase @@ -5949,11 +6408,11 @@ Võiksid kaaluda KeePassXC allalaadimislehel oleva AppImage’i kasutamist. Synchronizing from newer source %1 [%2] - Sünkroonimine uuema allikaga „%1” [%2] + Sünkimine uuema allikaga „%1” [%2] Synchronizing from older source %1 [%2] - Sünkroonimine vanema allikaga „%1” [%2] + Sünkimine vanema allikaga „%1” [%2] Deleting child %1 [%2] @@ -6040,6 +6499,25 @@ Võiksid kaaluda KeePassXC allalaadimislehel oleva AppImage’i kasutamist.Sisesta oma uuele andmebaasile kuvanimi ja soovi korral kirjeldus: + + NewEntryAttachmentsDialog + + Attachment name cannot be empty + Kaasatud faili nimi ei saa olla tühi. + + + Attachment with the same name already exists + Sellise nimega kaasatud fail on juba olemas. + + + Save attachment + Kaasatud faili salvestamine + + + New entry attachment + Uus kaasatud fail + + NixUtils @@ -6227,6 +6705,10 @@ Võiksid kaaluda KeePassXC allalaadimislehel oleva AppImage’i kasutamist.Unexpected EOF when writing private key Ootamatu faililõpp privaatvõtme kirjutamisel + + (encrypted) + (krüptitud) + OpenSSHKeyGenDialog @@ -6275,7 +6757,7 @@ Võiksid kaaluda KeePassXC allalaadimislehel oleva AppImage’i kasutamist. Export the following passkey entries. - + Eksportimisel on järgnevad pääsuvõtmekirjed. @@ -6348,15 +6830,15 @@ Kas soovid selle üle kirjutada? Import the following passkey: - + Importimisel on järgnev pääsuvõti: Import the following passkey to this entry: - + Importimisel on järgnev pääsuvõti sellesse kirjesse: Default passkeys group (Imported Passkeys) - + Vaikimisi pääsuvõtmete grupp („Imporditud pääsuvõtmed”) @@ -6379,25 +6861,27 @@ Kas soovid selle üle kirjutada? Open passkey file - + Pääsuvõtmefaili avamine Cannot import passkey - + Pääsuvõtme importimine pole võimalik Cannot import passkey file "%1". Data is missing. - + Pääsuvõtmefaili „%1” importimine pole võimalik. Andmed on puudu. Cannot import passkey file "%1". The following data is missing: %2 - + Pääsuvõtmefaili „%1” importimine pole võimalik. +Järgmised andmed on puudu: +%2 Cannot import passkey file "%1". Private key is missing or malformed. - + Pääsuvõtmefaili „%1” importimine pole võimalik. Privaatvõti on puudu või vigane. @@ -6578,10 +7062,6 @@ The following data is missing: Also choose from: Lisamärgid: - - Excluded characters: "0", "1", "l", "I", "O", "|", "﹒" - Määrab, kas välistada märgid nagu „0”, „O”, „1”, „l”, „I”, „|”, „﹒” - Exclude look-alike characters Sarnase välimusega märgid jäetakse välja @@ -6606,10 +7086,6 @@ The following data is missing: Word Count: Sõnade arv: - - Character Count: - Märkide arv: - Word Case: Täheregister: @@ -6622,10 +7098,6 @@ The following data is missing: Add custom wordlist Lisa kohandatud sõnaloend - - character - märk - Close Sulge @@ -6732,6 +7204,22 @@ Kas soovid selle üle kirjutada? Special Characters Erimärgid + + passwordLength + parooli_pikkus + + + Characters: %1 + Märkide arv: %1 + + + MIXED case + MÕLEMAD vaheldumisi + + + Excluded characters: "0", "1", "l", "I", "O", "|", "﹒", "B", "8", "G", "6" + Määrab, kas välistada märgid nagu „0”, „O”, „1”, „l”, „I”, „|”, „﹒”, „B”, „8”, „G”, „6” + PasswordWidget @@ -6799,6 +7287,21 @@ Kas soovid selle üle kirjutada? Märkide vahel „vajutatakse” &tabeldusklahvi + + PreviewEntryAttachmentsDialog + + Preview entry attachment + Kaasatud faili eelvaade + + + No preview available + Eelvaade pole saadaval + + + Image format not supported + Toetamata pildivorming + + QMessageBox @@ -7477,10 +7980,6 @@ Kas soovid selle üle kirjutada? Invalid word count %1 Sobimatu sõnade arv %1 - - The word list is too small (< 1000 items) - Sõnaloend on liiga väike (< 1000 elementi) - Title for the entry. Kirje pealkiri @@ -7625,10 +8124,6 @@ Kas soovid selle üle kirjutada? Exit interactive mode. Väljumine interaktiivsest režiimist. - - Format to use when exporting. Available choices are 'xml' or 'csv'. Defaults to 'xml'. - Eksportimisel kasutatav vorming. Valida on "xml" ja "csv". Vaikimisi "xml". - Exports the content of a database to standard output in the specified format. Andmebaasi sisu määratavas vormingus standardväljundisse eksportimine. @@ -8217,18 +8712,6 @@ Kernel: %3 %4 file empty fail on tühi - - malformed string - vigane string - - - missing closing quote - puuduv lõpujutumärk - - - %1: (row, col) %2,%3 - %1: (rida, veerg) %2,%3 - AES 256-bit AES: 256-bitine @@ -8472,11 +8955,12 @@ Kernel: %3 %4 Set the key file for the database. This option is deprecated, use --set-key-file instead. - + Andmebaasile võtmefaili määramine. +See argument on iganenud, kasuta parem "--set-key-file". Databases have been locked. - + Andmebaasid on lukustatud. Attestation not supported @@ -8564,7 +9048,7 @@ This option is deprecated, use --set-key-file instead. Origin is empty or not allowed - + Lähtedomeen on tühi või lubamatu Effective domain is not a valid domain @@ -8572,7 +9056,7 @@ This option is deprecated, use --set-key-file instead. Origin and RP ID do not match - + Lähtedomeeni ja sõltlase ID ei klapi No supported algorithms were provided @@ -8673,12 +9157,88 @@ This option is deprecated, use --set-key-file instead. Kiirklahvid - Unsupported KDF type, cannot decrypt json file - + Unknown passkeys error + Tundmatu tõrge pääsuvõtmega - Unknown passkeys error - + Invalid KDF iterations, cannot decrypt json file + Sobimatu KDF-i iteratsioonide arv, JSON-faili lahtikrüptimine pole võimalik + + + Unsupported format, ensure your Bitwarden export is password-protected + Toetamata vorming, vaata, et Bitwardeni eksport oleks parooliga kaitstud + + + Only PBKDF and Argon2 are supported, cannot decrypt json file + Toetatud on ainult PBKDF ja Argon2, JSON-faili lahtikrüptimine pole võimalik + + + Reset Shortcuts + Lähtesta kiirklahvid + + + Double click an action to change its shortcut + Kiirklahvi muutmiseks tee vastaval real topeltklõps. + + + Filter... + Filter… + + + Shortcut Conflict + Kiirklahvide konflikt + + + Shortcut %1 conflicts with '%2'. Overwrite shortcut? + Kiirklahviga %1 on juba seotud toiming „%2”. Kas soovid selle üle kirjutada? + + + Cannot generate valid passphrases because the wordlist is too short + Sobivaid paroolifraase pole võimalik genereerida, kuna sõnaloend on liiga lühike + + + Encrypted files are not supported. + Krüptitud faile ei toetata + + + Proton Pass Import + Proton Passist imporditud + + + Delete plugin data? + Plugina andmete kustutamise kinnitus + + + Delete plugin data from Entry(s)? + Kas kustutada kirjest plugina andmed?Kas kustutada kirjetest plugina andmed? + + + Passkey + Pääsuvõti + + + Format to use when exporting. Available choices are 'xml', 'csv' or 'html'. Defaults to 'xml'. + Eksportimisel kasutatav vorming. Valikus on „xml“, „csv“ ja „html“. Vaikimisi vorming on „xml“. + + + start minimized to the system tray + Käivitamine süsteemisalve minimeerituna. + + + malformed string, possible unescaped delimiter + vigases vormis sõne, võimalik mitteeemaldatud eraldaja + + + missing closing delimiter + lõpetav eraldaja on puudu + + + %1, row: %2, column: %3 + %1, rida: %2, veerg: %3 + + + Tags + Sildid @@ -8715,6 +9275,37 @@ This option is deprecated, use --set-key-file instead. Sisemine zlib-i tõrge: + + RemoteHandler + + Command `%1` did not finish in time. Process was killed. + Käsk „%1” ei lõpetanud tööd mõistliku aja jooksul. Protsess lõpetati sunniviisiliselt. + + + Failed to upload merged database. Command `%1` did not finish in time. Process was killed. + Mestitud andmebaasi üleslaadmine ebaõnnestus. Käsk „%1” ei lõpetanud tööd mõistliku aja jooksul. Protsess lõpetati sunniviisiliselt. + + + Invalid download parameters provided. + Anti sobimatud allalaadimisparameetrid. + + + Command `%1` failed to download database. + Käsul „%1” ei õnnestunud andmebaasi alla laadida. + + + Invalid database pointer or upload parameters provided. + Anti sobimatu adnmebaasiviide või sobimatud üleslaadimisparameetrid. + + + Command `%1` exited with status code: %2 + Käsk „%1” lõpetas töö olekukoodiga %2 + + + Failed to upload merged database. Command `%1` exited with status code: %2 + Mestitud andmebaasi üleslaadmine ebaõnnestus. Käsk „%1” lõpetas töö olekukoodiga %2 + + ReportsWidgetBrowserStatistics @@ -8781,6 +9372,10 @@ This option is deprecated, use --set-key-file instead. Exclude from reports Jäetakse aruannetest välja + + Expire Entry(s)… + Märgi kirje aegunuks…Märgi kirjed aegunuks… + Only show entries that have a URL Näidatakse ainult kirjeid, millel on URL määratud @@ -8797,36 +9392,33 @@ This option is deprecated, use --set-key-file instead. (Expired) (aegunud) + + Delete plugin data from Entry(s)… + Kustuta kirjest plugina andmed…Kustuta kirjetest plugina andmed… + ReportsWidgetHealthcheck - Hover over reason to show additional details. Double-click entries to edit. - Põhjuse kohta täpsema teabe saamiseks hoia hiirekursorit selle kohal. Kirje muutmiseks tee topeltklõps. + Show expired entries + Näidatakse ka aegunud kirjeid - Bad - Password quality - Kohutav + (Expired) + (aegunud) + + + Hover over reason to show additional details. Double-click entries to edit. + Põhjuse kohta täpsema teabe saamiseks hoia hiirekursorit selle kohal. Kirje muutmiseks tee topeltklõps. Bad — password must be changed Kohutav – palun muuda parooli - - Poor - Password quality - Kehv - Poor — password should be changed Kehv – parooli tuleks muuta - - Weak - Password quality - Nõrk - Weak — consider changing the password Nõrk – kaalu parooli muutmist @@ -8875,18 +9467,14 @@ This option is deprecated, use --set-key-file instead. Exclude from reports Jäetakse aruannetest välja - - Show expired entries - Näidatakse ka aegunud kirjeid + + Expire Entry(s)… + Märgi kirje aegunuks…Märgi kirjed aegunuks… Show entries that have been excluded from reports Näidatakse ka muidu aruannetest välja jäetavaid kirjeid - - (Expired) - (aegunud) - ReportsWidgetHibp @@ -8982,6 +9570,10 @@ This option is deprecated, use --set-key-file instead. Exclude from reports Jäetakse aruannetest välja + + Expire Entry(s)… + Märgi kirje aegunuks…Märgi kirjed aegunuks… + ReportsWidgetPasskeys @@ -9039,15 +9631,15 @@ This option is deprecated, use --set-key-file instead. The passkey file will be vulnerable to theft and unauthorized use, if left unsecured. Are you sure you want to continue? - + Kui jätad pääsuvõtmetega faili turvamata, võidakse see varastada või seda ilma loata kasutada. Kas oled kindel, et soovid jätkata? Please wait, list of entries with passkeys is being updated… - + Palun oota, pääsuvõtmega kirjete nimekirja uuendatakse… No entries with passkeys. - + Ühtegi pääsuvõtmega kirjet pole. @@ -9223,6 +9815,14 @@ This option is deprecated, use --set-key-file instead. No agent running, cannot list identities. Ükski agent ei tööta, identiteete pole võimalik loetleda. + + Failed to remove all SSH identities from agent. + Kõigi identiteetide eemaldamine SSH agendilt ebaõnnestus. + + + All SSH identities removed from agent. + Kõik identiteedid SSH agendilt eemaldatud. + SearchHelpWidget @@ -9397,11 +9997,11 @@ This option is deprecated, use --set-key-file instead. <html><head/><body><p>This setting does not override disabling recycle bin prompts </p></body></html> - + <html><head/><body><p>Selle ruudu märkimisel pole mõju, kui prügikasti viskamisel kinnituse küsimine on välja lülitatud.</p></body></html> <html><head/><body><p>This improves compatibility with certain applications which search for password without unlocking the database first.</p><p>But enabling this may also crash the client if the database can not be unlocked within a certain timeout. (Usually 25s, but may be a different value set in applications.) </p></body></html> - + <html><head/><body><p>Märkimine parandab ühilduvust teatud rakendustega, mis otsivad parooli ilma esmalt andmebaasi lukku avamata.</p><p>Samas võib see põhjustada kliendi kokkujooksmise, kui andmebaasi lukku piisavalt kiiresti ei avata. (Tavaline ajalimiit on 25 s, aga see võib eri rakenduste puhul erineda.)</p></body></html> @@ -9508,29 +10108,6 @@ This option is deprecated, use --set-key-file instead. Eksportimine asukohta „%1” - - ShortcutSettingsWidget - - Double click an action to change its shortcut - Kiirklahvi muutmiseks tee vastaval real topeltklõps. - - - Shortcut Conflict - Kiirklahvide konflikt - - - Filter... - Filter - - - Shortcut %1 conflicts with '%2'. Overwrite shortcut? - Kiirklahviga %1 on juba seotud toiming „%2”. Kas soovid selle üle kirjutada? - - - Reset Shortcuts - Lähtesta kiirklahvid - - TagModel @@ -9819,14 +10396,18 @@ Näide: JBSWY3DPEHPK3PXP No hardware keys detected riistvaralisi võtmeid ei tuvastatud - - <p>If you own a <a href="https://www.yubico.com/">YubiKey</a> or <a href="https://onlykey.io">OnlyKey</a>, you can use it for additional security.</p><p>The key requires one of its slots to be programmed as <a href="https://docs.yubico.com/yesdk/users-manual/application-otp/challenge-response.html">HMAC-SHA1 Challenge-Response</a>.</p> - <p>Kui sul on <a href="https://www.yubico.com/">YubiKey</a> või <a href="https://onlykey.io">OnlyKey</a> turvavõti, võid lisaturvalisuse nimel seda kasutada.</p><p>Võtme ühe pesa peab programmeerima <a href="https://docs.yubico.com/yesdk/users-manual/application-otp/challenge-response.html">HMAC-SHA1 pretensiooni ja vastusena</a>.</p> - Refresh hardware keys Värskenda riistvaraliste võtmete loendit + + <p>If you own a <a href="https://www.yubico.com/">YubiKey</a> or <a href="https://onlykey.io">OnlyKey</a>, you can use it for additional security.</p><p>The key requires one of its slots to be programmed with <a href="https://keepassxc.org/docs/#faq-yubikey-howto">Challenge-Response</a>.</p> + <p>Kui sul on <a href="https://www.yubico.com/">YubiKey</a> või <a href="https://onlykey.io">OnlyKey</a> turvavõti, võid lisaturvalisuse nimel seda kasutada.</p><p>Võtme ühe pesa peab programmeerima <a href="https://keepassxc.org/docs/#faq-yubikey-howto">pretensiooni ja vastusena</a>.</p> + + + Hardware keys found, but no slots are configured + Leiti riistvaraline võti, kuid ühtki pesa pole seadistatud + YubiKeyInterfacePCSC diff --git a/share/translations/keepassxc_fi.ts b/share/translations/keepassxc_fi.ts index 70e650e97..57a12471c 100644 --- a/share/translations/keepassxc_fi.ts +++ b/share/translations/keepassxc_fi.ts @@ -217,18 +217,50 @@ You must restart the application to set the new language. Would you like to restart now? Ohjelma täytyy käynnistää uudelleen, jotta uusi kieli voidaan ottaa käyttöön. Haluatko käynnistää uudelleen nyt? - - Reset Settings? - Palauta asetukset? - - - Are you sure you want to reset all general and security settings to default? - Haluatko varmasti palauttaa kaikki yleiset ja turvallisuusasetukset oletuksiin? - Select backup storage directory Valitse varmuuskopion hakemistopolku + + Confirm Reset + Vahvista palauttaminen + + + Are you sure you want to reset all settings to default? + Haluatko varmasti palauttaa kaikki asetukset oletuksiinsa? + + + Import KeePassXC Settings + Tuo KeePassXC-asetukset + + + Failed to import settings from %1, not a valid settings file. + Ei voitu tuoda asetuksia tiedostosta %1: ei ole kelvollinen asetustiedosto. + + + Export KeePassXC Settings + Vie KeePassXC-asetukset + + + Small + + + + Normal + + + + Medium + + + + Large + + + + Custom + + ApplicationSettingsWidgetGeneral @@ -280,25 +312,6 @@ Include beta releases when checking for updates Sisällytä betajulkaisut päivityksiä tarkistaessa - - On database unlock, show entries that - Tietokannan avauksen yhteydessä, näytä tietueet jotka - - - have expired - On database unlock, show entries that... - ovat vanhentuneet - - - days - On database unlock, show entries that will expire within %1 days - päivää - - - will expire within - On database unlock, show entries that... - vanhentuvat ajan sisällä - File Management Tiedostohallinta @@ -323,22 +336,10 @@ Backup database file before saving Ota tietokannasta varmuuskopio ennen tallentamista - - Backup destination - Varmuuskopion sijainti - - - Specifies the database backup file location. Occurrences of "{DB_FILENAME}" are replaced with the filename of the saved database without extension. {TIME:<format>} is replaced with the backup time, see https://doc.qt.io/qt-5/qdatetime.html#toString. <format> defaults to format string "dd_MM_yyyy_hh-mm-ss". - Määrittää tietokannan varmuuskopion sijainnin. "{DB_FILENAME}" -merkkijonot korvataan tietokannan tiedostonimellä ilman tiedostopäätettä. {TIME:<format>} korvataan varmuuskopion aikaleimalla (https://doc.qt.io/qt-5/qdatetime.html#toString).<format>Aikaleiman vakiomuoto on "dd_MM_yyyy_hh-mm-ss". - {DB_FILENAME}.old.kdbx {DB_FILENAME}.old.kdbx - - Choose... - Valitse... - Use alternative saving method (may solve problems with Dropbox, Google Drive, GVFS, etc.) Käytä vaihtoehtoista tallennusmetodia (voi ratkaista ongelmia Dropboxin, Google Driven GVFS:n, ymv. kanssa) @@ -505,6 +506,71 @@ Remember last typed entry for: Muista edellinen syötetty tietue: + + On database unlock, show entries that will expire within + Tietokannan lukitusta avattaessa näytä tietueet, jotka vanhenevat + + + On database unlock, show entries that will expire within + Tietokannan lukitusta avattaessa näytä tietueet, jotka vanhenevat + + + days + number of days warning for password expiration + päivää + + + Destination format: + Kohdemuoto: + + + <html><head/><body><p><span style=" font-weight:600;">{DB_FILENAME}</span> is replaced with the filename of the saved database without extension</p><p><span style=" font-weight:600;">{TIME:&lt;format&gt;}</span> is replaced with the specified time format (default: dd_MM_yyyy_hh-mm-ss)</p><p>See the User Guide for more details</p></body></html> + <html><head/><body><p><span style=" font-weight:600;">{DB_FILENAME}</span> korvataan tallennettavan tietokannan päätteettömällä tiedostonimellä</p><p><span style=" font-weight:600;">{TIME:&lt;format&gt;}</span> korvataan määrityksen mukaisella aikaleimalla (oletus: pp_KK_vvvv_tt-mm-ss)</p><p>Lisätietoa löytyy käyttöoppaasta</p></body></html> + + + Choose folder... + Valitse kansio… + + + Show confirmation before moving entries to recycle bin + Pyydä vahvistus ennen tietueiden siirtämistä roskakoriin + + + Copy data on double clicking field in entry view + Kopioi tiedot kaksoisnapsautettaessa kenttää tietuenäkymässä + + + Show toolbar + Näytä työkalupalkki + + + Show the menu bar by pressing the Alt key + Näytä valikko painettaessa Alt-näppäintä + + + Show menubar + Näytä valikkorivi + + + Import settings… + Tuo asetukset… + + + Export settings… + Vie asetukset… + + + Open browser on double clicking URL field in entry view + Avaa selain kaksoisnapsautettaessa verkko-osoitekenttää tietuenäkymässä + + + Font size: + + + + Font size selection + + ApplicationSettingsWidgetSecurity @@ -570,18 +636,6 @@ Hide passwords in the entry preview panel Piilota salasanat tietueiden esikatselupaneelissa - - Hide entry notes by default - Piilota tietueiden muistiinpanot - - - Move entries to recycle bin without confirmation - Siirrä tietueet roskakoriin ilman varmistusta - - - Enable double click to copy the username/password entry columns - Ota tuplaklikkaus käyttöön kopioidaksesi käyttäjätunnuksen/salasanan sarakkeita - Privacy Yksityisyys @@ -594,6 +648,18 @@ Hide TOTP in the entry preview panel Piilota TOTP merkinnän esikatselupaneelista + + Lock databases when switching user + Lukitse tietokanta, jos käyttäjää vaihdetaan + + + Lock Options + Lukitse valinnat + + + Hide notes in the entry preview panel + Piilota muistiinpanot tietueen esikatselupaneelista + AutoType @@ -641,20 +707,6 @@ Entry does not have attribute for PICKCHARS: %1 Merkintä ei sisällä attribuuttia PICKCHARS: %1 - - Invalid conversion type: %1 - Virheellinen muunnoksen tyyppi: %1 - - - Invalid conversion syntax: %1 - Virheellinen muutoksen syntaksi: %1 - - - Invalid regular expression syntax %1 -%2 - Virheellinen Regex-syntaksi %1 -%2 - Invalid placeholder: %1 Virheellinen paikkamerkki: %1 @@ -714,7 +766,7 @@ Trying to send invalid keyboard symbol. - + Yritettiin lähettää virheellistä näppäimistösymbolia. @@ -882,28 +934,29 @@ Valitse tietokanta, johon tiedot tallennetaan. KeePassXC - Passkey credentials - KeePassXC - Passkeyn tunnistetiedot + KeePassXC - Pääsyavaimen tunnistetiedot Add to existing entry - + Lisää olemassa olevaan tietueeseen Existing passkey found. Do you want to register a new passkey for: - + Olemassa oleva pääsyavain löytyi +Haluatko rekisteröidä uuden pääsyavaimen sivustolle: Select the existing passkey and press Update to replace it. - + Valitse olemassa oleva pääsyavain ja klikkaa Päivitä korvataksesi se. Authenticate passkey credentials for: - + Kirjaudu pääsyavaimella sivustolle: Do you want to register a passkey for: - + Haluatko rekisteröidä pääsyavaimen sivustolle: @@ -951,7 +1004,7 @@ Haluatko poistaa tietueen? %1 (Passkey) - %1 (passkey) + %1 (pääsyavain) KeePassXC - Create a new group @@ -979,24 +1032,25 @@ Haluatko poistaa tietueen? Passkey - Passkey + Pääsyavain KeePassXC - Passkey credentials - KeePassXC - Passkeyn tunnistetiedot + KeePassXC - Pääsyavaimen tunnistetiedot Register a new passkey to this entry: - + Rekisteröi uusi pääsyavain tähän tietueeseen: KeePassXC - Update passkey - + KeePassXC - Päivitä pääsyavain Entry already has a passkey. Do you want to overwrite the passkey in %1 - %2? - + Tietueella on jo pääsyavain. +Haluatko ylikirjoittaa pääsyavaimen %1 - %2? Register @@ -1021,10 +1075,6 @@ Do you want to overwrite the passkey in %1 - %2? General Yleistä - - Browsers installed as snaps are currently not supported. - Snapin kautta asennetut selaimet eivät ole tällä hetkellä tuettuja. - Enable integration for these browsers: Käytä integraatiota seuraaville selaimille: @@ -1196,18 +1246,6 @@ Do you want to overwrite the passkey in %1 - %2? Custom extension ID Mukautetun selainlaajennuksen ID - - Due to Snap sandboxing, you must run a script to enable browser integration.<br />You can obtain this script from %1 - Snap:in hiekkalaatikon takia sinun täytyy suorittaa komentosarja jotta voit aktivoida selainintegraation.<br />Voit ladata komentosarjan osoitteesta %1 - - - KeePassXC-Browser is needed for the browser integration to work. <br />Download it for %1 and %2 and %3. %4 - KeePassXC-Browser tarvitaan selainintegraation toimimista varten.<br />Lataa se seuraaville selaimille: %1, %2 ja %3. %4 - - - Please see special instructions for browser extension use below - Katso yksityiskohtaisemmat ohjeet selainlaajennuksen käyttöön alta - Executable Files Suoritettavat tiedostot @@ -1250,10 +1288,18 @@ Do you want to overwrite the passkey in %1 - %2? Allows using insecure http://localhost with passkeys for testing purposes. - + Sallii turvattoman http://localhost:in käyttämisen pääsyavainten kanssa testaamistarkoituksessa. Allow using localhost with passkeys + Salli localhostin käyttö pääsyavainten kanssa + + + KeePassXC-Browser is needed for the browser integration to work. <br />Download it for %1 and %2 and %3. + KeePassXC-Browser tarvitaan selainintegraation toimimista varten.<br />Lataa se seuraaville selaimille: %1, %2 ja %3. + + + Browsers installed using Snap or Flatpak are not supported with exception to Firefox installed using Snap. @@ -1398,6 +1444,20 @@ Do you want to overwrite the passkey in %1 - %2? Imported from CSV file: %1 Tuotu CSV-tiedostosta: %1 + + No Title Selected + Otsikkoa ei ole valittu + + + No title column was selected, entries will be hard to tell apart. +Are you sure you want to import? + Tietueet voi olla hankala erottaa toisistaan, sillä otsikkosaraketta ei ole valittu. +Oletko varma, että haluat jatkaa tuontia? + + + Tags + Tagit + CsvParserModel @@ -1461,6 +1521,14 @@ Tietokannan varmuuskopio paikannettu: %2 Recycle Bin Roskakori + + Database file read error. + + + + No file path was provided. + + DatabaseOpenDialog @@ -1609,14 +1677,6 @@ Jos et halua nähdä tätä virhettä uudestaan, mene "Tietokannan asetukse <p>In addition to a password, you can use a secret file to enhance the security of your database. This file can be generated in your database's security settings.</p><p>This is <strong>not</strong> your *.kdbx database file!</p> <p>Pääsalasanan lisäksi voit käyttää salaista tiedostoa tietokantasi tietoturvan vahvistamiseksi. Tämä tiedosto voidaan tarvittaessa luoda tietokantasi turvallisuusasetuksista.</p><p>Tämä salainen tiedosto <strong>ei</strong> ole *.kdbx -tietokantatiedosto!</p> - - Click to add a key file. - Klikkaa asettaaksesi avaintiedosto - - - <a href="#" style="text-decoration: underline">I have a key file</a> - <a href="#" style="text-decoration: underline">Minulla on avaintiedosto</a> - Use hardware key [Serial: %1] Käytä laiteavainta [Sarjanumero: %1] @@ -1653,6 +1713,18 @@ Oletko varma, että haluat jatkaa tämän tiedoston käyttämistä?Refresh Hardware Keys Uudista laiteavaimet + + Click to add a key file. + Klikkaa asettaaksesi avaintiedosto + + + <a href="#" style="text-decoration: underline">I have a key file</a> + <a href="#" style="text-decoration: underline">Minulla on avaintiedosto</a> + + + Hardware keys found, but no slots are configured. + + DatabaseSettingWidgetMetaData @@ -1687,6 +1759,22 @@ Oletko varma, että haluat jatkaa tämän tiedoston käyttämistä?Maintenance Ylläpito + + KeeShare + KeeShare + + + Secret Service Integration + Secret Service -integraatio + + + Remote Sync + Etäsynkronointi + + + Database Settings: %1 + + DatabaseSettingsWidgetBrowser @@ -1857,14 +1945,14 @@ Oletko varma, että haluat jatkaa ilman salasanaa? Weak password Heikko salasana - - You must enter a stronger password to protect your database. - Sinun on syötettävä vahvempi salsana tietokantasi suojaamiseksi. - This is a weak password! For better protection of your secrets, you should choose a stronger password. Tämä on heikko salsana! SInun tulisi valita vahvempi salsana tietojesi parempaa suojausta varten. + + The provided password does not meet the minimum quality requirement. + Annettu salasana ei täytä laadullisia minimivaatimuksia. + DatabaseSettingsWidgetEncryption @@ -2156,6 +2244,50 @@ removed from the database. Autosave delay since last change checkbox Muutosta seuraavan automaattitallennuksen viiveen valintalaatikko + + Public Database Metadata + + + + Warning: the following settings are not encrypted. + Varoitus: seuraavia asetuksia ei ole salattu. + + + Display name: + Näyttönimi: + + + Publically visible display name used on the unlock dialog + Lukituksen avausikkunassa julkisesti näkyvä näyttönimi + + + Database public display name + Tietokannan julkinen näyttönimi + + + Display color: + Näyttöväri: + + + Publically visible color used on the unlock dialog + Lukituksen avausikkunassa julkisesti näkyvä väri + + + Database public display color chooser + Tietokannan julkisen näyttövärin valitsin + + + Clear + Tyhjennä + + + Display icon: + Näyttökuvake: + + + Select Database Icon + Valitse tietokantakuvake + DatabaseSettingsWidgetKeeShare @@ -2251,6 +2383,141 @@ removed from the database. Tietokannan kuvauskenttä + + DatabaseSettingsWidgetRemote + + Sync Commands + Synkronoinnin komennot + + + Remove + Poista + + + Command Settings + Komentoasetukset + + + Name + Nimi + + + Save + Tallenna + + + Download + Lataa + + + Command: + Komento: + + + Download command field + Latauskomento epäonnistui + + + e.g.: "sftp user@hostname" or "scp user@hostname:DatabaseOnRemote.kdbx {TEMP_DATABASE}" + Esim. "sftp user@hostname" tai "scp user@hostname:DatabaseOnRemote.kdbx {TEMP_DATABASE}" + + + Input: + Syöte: + + + Download input field + Lataa syöte + + + Upload + Lähetä + + + Upload command field + Lähetä-komento epäonnistui + + + e.g.: "sftp user@hostname" or "scp {TEMP_DATABASE} user@hostname:DatabaseOnRemote.kdbx" + Esim. "sftp user@hostname" tai "scp {TEMP_DATABASE user@hostname:DatabaseOnRemote.kdbx" + + + Upload input field + Lähetyksen syöte + + + Name cannot be empty. + Nimi ei voi olla tyhjä. + + + Test + Testaa + + + Download command cannot be empty. + Latauskomento ei voi olla tyhjä. + + + Download failed with error: %1 + Lataus epäonnistui virheellä: + + + Download finished, but file %1 could not be found. + Lataus päättyi, mutta tiedostoa %1 ei löydy. + + + Download successful. + Lataus onnistui. + + + Save Remote Settings + Tallenna asetukset + + + You have unsaved changes. Do you want to save them? + Sinulla on tallentamattomia asetuksia. Haluatko tallettaa ne? + + + e.g.: +get DatabaseOnRemote.kdbx {TEMP_DATABASE} +exit +--- +{TEMP_DATABASE} is used as placeholder to store the database in a temporary location +The command has to exit. In case of `sftp` as last command `exit` has to be sent + + Esim. +get DatabaseOnRemote.kdbx {TEMP_DATABASE} +exit +--- +{TEMP_DATABASE} -muuttujaa käytetään paikkamerkkinä tietokannan välikaikaisena sijaintina. +Komennon täytyy suoriutua. `sftp` -komennon ollessa viimeinen komento, `exit` täytyy lähettää. + + + + e.g.: +put {TEMP_DATABASE} DatabaseOnRemote.kdbx +exit +--- +{TEMP_DATABASE} is used as placeholder to store the database in a temporary location +The command has to exit. In case of `sftp` as last command `exit` has to be sent + + Esim. +put {TEMP_DATABASE} DatabaseOnRemote.kdbx +exit +--- +{TEMP_DATABASE} -muuttujaa käytetään paikkamerkkinä tietokannan välikaikaisena sijaintina. +Komennon täytyy suoriutua. `sftp` -komennon ollessa viimeinen komento, `exit` täytyy lähettää. + + + + Timeout: + + + + seconds + sekuntia + + DatabaseTabWidget @@ -2324,6 +2591,11 @@ Tämä on selkeä virhe, joten ota yhteyttä kehittäjätiimiin. Database tab name modifier %1 [Lukittu] + + %1 [Temporary] + Database tab name modifier + %1 [Väliaikainen] + DatabaseWidget @@ -2447,26 +2719,6 @@ Tallenna muutokset? File has changed Tiedosto on muuttunut - - The database file has changed. Do you want to load the changes? - Tietokantatiedosto on muuttunut. Haluatko ladata muutokset? - - - Merge Request - Yhdistämispyyntö - - - The database file has changed and you have unsaved changes. -Do you want to merge your changes? - Tietokantatiedosto on muuttunut, ja sinulla on tallentamattomia muutoksia. -Haluatko yhdistää muutoksesi? - - - Could not open the new database file while attempting to autoreload. -Error: %1 - Uutta tietokantaa ei voitu avata automaattisen uudelleenlatauksen yhteydessä. -Virhe: %1 - Disable safe saves? Ota turvallinen tallennus pois käytöstä? @@ -2518,6 +2770,86 @@ Ota turvallinen tallennus pois käytöstä ja yritä uudelleen? Database tab name modifier %1 [Uusi tietokanta] + + Remote Sync did not contain any download or upload commands. + Etäsynkronointi ei sisältänyt yhtään lataus- tai lähetyskomentoa. + + + Remote sync '%1' completed successfully! + Etäsynkronointi '%1' suoritettiin onnistuneesti! + + + Remote sync '%1' failed: %2 + Etäsynkronointi '%1' epäonnistui: %2 + + + Error while saving database %1: %2 + Tietokannan %1 tallennus epäonnistui: %2 + + + Downloading... + Ladataan... + + + Uploading... + Lähetetään... + + + Syncing... + Synkronoidaan... + + + Remove passkey from entry + Poista pääsyavain tietueesta + + + Do you want to remove the passkey from this entry? + Haluatko poistaa pääsyavaimen tästä tietueesta? + + + The database file "%1" was modified externally + + + + Do you want to load the changes? + + + + Reload database + + + + Reloading database… + + + + Reload canceled + + + + Reload successful + + + + Reload pending user action… + + + + The database file "%1" was modified externally.<br>How would you like to proceed?<br><br>Merge all changes<br>Ignore the changes on disk until save<br>Discard unsaved changes + + + + The database file "%1" was modified externally.<br>How would you like to proceed?<br><br>Merge all changes then save<br>Overwrite the changes on disk<br>Discard unsaved changes + + + + Database file overwritten. + + + + Database file on disk cannot be unlocked with current credentials.<br>Enter new credentials and/or present hardware key to continue. + + EditEntryWidget @@ -2569,10 +2901,6 @@ Ota turvallinen tallennus pois käytöstä ja yritä uudelleen? n/a ei saatavilla - - (encrypted) - (salattu) - Select private key Valitse yksityinen avain @@ -2675,6 +3003,10 @@ Haluatko korjata sen? %n year(s) %n vuosi%n vuotta + + Failed to decrypt SSH key, ensure password is correct. + SSH-avaimen purku epäonnistui. Varmista, että salasana on oikein. + EditEntryWidgetAdvanced @@ -2846,18 +3178,10 @@ Haluatko korjata sen? Skip Auto-Submit for this entry Älä salli automaattisyöttöä tälle tietueelle - - Only send this setting to the browser for HTTP Auth dialogs. If enabled, normal login forms will not show this entry for selection. - Lähetä tämä tietue vain HTTP-autentikaatiodialogeihin. Jos asetus on päällä, tavalliset kirjautumiskentät eivät näytä tätä tietuetta listassa. - Use this entry only with HTTP Basic Auth Käytä tietuetta vain HTTP Basic -autentikaatioon - - Do not send this setting to the browser for HTTP Auth dialogs. If enabled, HTTP Auth dialogs will not show this entry for selection. - Älä lähetä tätä tietuetta HTTP-autentikaatiodialogeihin. Jos asetus on päällä, tämä tietue näkyy vain tavallisissa kirjautumiskentissä. - Do not use this entry with HTTP Basic Auth Älä käytä tätä tietuetta HTTP Basic -autentikaatioon @@ -2876,11 +3200,19 @@ Haluatko korjata sen? These settings affect the entry's behaviour with the browser extension. - + Nämä asetukset vaikuttavat tietueen käytökseen selainlaajennuksen kanssa. Additional URLs - + Lisäosoitteet + + + Only send this entry to the browser for HTTP Auth dialogs. If enabled, normal login forms will not show this entry for selection. + Lähetä tämä tietue vain HTTP-autentikaatiodialogeihin. Jos asetus on päällä, tavalliset kirjautumiskentät eivät näytä tätä tietuetta listassa. + + + Do not send this entry to the browser for HTTP Auth dialogs. If enabled, HTTP Auth dialogs will not show this entry for selection. + Älä lähetä tätä tietuetta HTTP-autentikaatiodialogeihin. Jos asetus on päällä, tämä tietue näkyy vain tavallisissa kirjautumiskentissä. @@ -3104,6 +3436,10 @@ Haluatko korjata sen? seconds sekuntia + + Clear agent + + EditGroupWidget @@ -3546,6 +3882,24 @@ Tämä voi vikaannuttaa tietoa käyttävän liitännäisen. %1 - Clone %1 - Klooni + + Passkey + Pääsyavain + + + Invalid conversion type: %1 + Virheellinen muunnoksen tyyppi: %1 + + + Invalid conversion syntax: %1 + Virheellinen muutoksen syntaksi: %1 + + + Invalid regular expression syntax %1 +%2 + Virheellinen Regex-syntaksi %1 +%2 + EntryAttachments @@ -3554,6 +3908,21 @@ Tämä voi vikaannuttaa tietoa käyttävän liitännäisen. Tiedostoa "%1" ei voitu avata + + EntryAttachmentsDialog + + Form + Lomake + + + File name + + + + File contents... + + + EntryAttachmentsModel @@ -3591,14 +3960,6 @@ Tämä voi vikaannuttaa tietoa käyttävän liitännäisen. Remove Poista - - Rename selected attachment - Nimeä valittu liite uudelleen - - - Rename - Nimeä uudelleen - Open selected attachment Avaa valittu liite @@ -3714,6 +4075,18 @@ Would you like to overwrite the existing attachment? Liitetiedosto "%1" on jo olemassa. Haluatko ylikirjoittaa sen? + + New + + + + Preview + Esikatselu + + + Failed to preview an attachment: Attachment not found + + EntryAttributesModel @@ -3912,6 +4285,10 @@ Haluatko ylikirjoittaa sen? Background Color Taustaväri + + Group Path + + EntryPreviewWidget @@ -4307,6 +4684,14 @@ Voit aktivoida DuckDuckGon kuvakepalvelun sovelluksen suojausasetuksista.Url Osoite + + Could not load key file. + + + + Could not open remote database. Password or key file may be incorrect. + + ImportWizardPageSelect @@ -4410,6 +4795,44 @@ Voit aktivoida DuckDuckGon kuvakepalvelun sovelluksen suojausasetuksista.KeePass1 Database KeePass1-tietokanta + + Proton Pass (.json) + Proton Pass (.json) + + + Proton Pass JSON Export + Proton Pass -JSON-vienti + + + Temporary Database + + + + Command: + Komento: + + + e.g.: "sftp user@hostname" or "scp user@hostname:DatabaseOnRemote.kdbx {TEMP_DATABASE}" + Esim. "sftp user@hostname" tai "scp user@hostname:DatabaseOnRemote.kdbx {TEMP_DATABASE}" + + + Input: + Syöte: + + + e.g.: +get DatabaseOnRemote.kdbx {TEMP_DATABASE} +exit +--- +{TEMP_DATABASE} is used as placeholder to store the database in a temporary location +The command has to exit. In case of `sftp` as last commend `exit` has to be sent + + + + + Remote Database (.kdbx) + Etätietokanta (.kdbx) + KMessageWidget @@ -5495,7 +5918,7 @@ Haluatko jatkaa käyttämällä tätä tiedostoa? Show Menubar - + Näytä työkalupalkki Show Toolbar @@ -5550,12 +5973,6 @@ Tätä versiota ei ole tarkoitettu päivittäiseen käyttöön. Expect some bugs and minor issues, this version is meant for testing purposes. HUOM: Käytät KeePassXC:n esiversiota! Bugeja ja ongelmia voi esiintyä. Tämä versio on tarkoitettu vain testikäyttöön. - - - WARNING: Your Qt version may cause KeePassXC to crash with an On-Screen Keyboard. -We recommend you use the AppImage available on our downloads page. - VAROITUS: Qt-versiosi voi aiheuttaa KeePassXC:n kaatumisen näytöllä näkyvällä näppäimistöllä! -Suosittelemme, että käytät AppImagea, jonka voit hakea lataussivustoltamme. No Tags @@ -5623,11 +6040,15 @@ Suosittelemme, että käytät AppImagea, jonka voit hakea lataussivustoltamme. Passkeys… - Passkeyt... + Pääsyavaimet... Import Passkey - Tuo passkey + Tuo pääsyavain + + + Remote S&ync… + Etäs&ynkronointi... Quit Application @@ -5703,7 +6124,7 @@ Suosittelemme, että käytät AppImagea, jonka voit hakea lataussivustoltamme. Show Passkeys - Näytä passkeyt + pääsyavaimet Clone Entry @@ -5733,6 +6154,10 @@ Suosittelemme, että käytät AppImagea, jonka voit hakea lataussivustoltamme.Show Password Generator Näytä salasanageneraattori + + Remove Passkey From Entry + Poista pääsyavain tietueesta + Perform Auto-Type: {USERNAME} Suorita automaattisyöttö: {USERNAME} @@ -5847,7 +6272,7 @@ Suosittelemme, että käytät AppImagea, jonka voit hakea lataussivustoltamme. Toggle Show Menubar - + Aseta: näytä työkalupalkki Toggle Show Toolbar @@ -5877,6 +6302,34 @@ Suosittelemme, että käytät AppImagea, jonka voit hakea lataussivustoltamme.Toggle Allow Screen Capture Aseta: salli kuvankaappaus + + Show Group Panel + Näytä ryhmäpaneeli + + + Toggle Show Group Panel + Näytä tai piilota ryhmäpaneeli + + + Setup Remote Sync… + Määritä etäsynkronointi + + + Password Generator + Salasanageneraattori + + + E&xpire Entry… + + + + Clear SSH Agent + + + + Clear all identities in ssh-agent + + ManageDatabase @@ -6027,6 +6480,25 @@ Suosittelemme, että käytät AppImagea, jonka voit hakea lataussivustoltamme.Ole hyvä ja täytä tietokantasi nimi ja vapaaehtoinen kuvaus: + + NewEntryAttachmentsDialog + + Attachment name cannot be empty + + + + Attachment with the same name already exists + + + + Save attachment + Tallenna liite + + + New entry attachment + + + NixUtils @@ -6214,6 +6686,10 @@ Suosittelemme, että käytät AppImagea, jonka voit hakea lataussivustoltamme.Unexpected EOF when writing private key Odottamaton EOF yksityistä avainta kirjoittaessa + + (encrypted) + (salattu) + OpenSSHKeyGenDialog @@ -6238,7 +6714,7 @@ Suosittelemme, että käytät AppImagea, jonka voit hakea lataussivustoltamme.PasskeyExportDialog KeePassXC - Passkey Export - KeePassXC - Passkeyn vienti + KeePassXC - Pääsyavaimen vienti Filenames will be generated with title and .passkey file extension. @@ -6262,14 +6738,14 @@ Suosittelemme, että käytät AppImagea, jonka voit hakea lataussivustoltamme. Export the following passkey entries. - + Vie seuraavat pääsyavaintietueet. PasskeyExporter KeePassXC: Passkey Export - KeePassXC: Passkey-vienti + KeePassXC: Pääsyavaimen vienti File "%1.passkey" already exists. @@ -6296,7 +6772,7 @@ haluatko korvata sen? PasskeyImportDialog KeePassXC - Passkey Import - KeePassXC - Passkey-vienti + KeePassXC - Pääsyavaimen vienti Username: %1 @@ -6312,7 +6788,7 @@ haluatko korvata sen? Import Passkey - Tuo passkey + Tuo pääsyavain Import @@ -6336,22 +6812,22 @@ haluatko korvata sen? Import the following passkey: - + Tuo seuraava pääsyavain: Import the following passkey to this entry: - + Tuo seuraava pääsyavain tähän tietueeseen: Default passkeys group (Imported Passkeys) - + Pääsyavainten oletusryhmä (Tuodut pääsyavaimet) PasskeyImporter Passkey file - Passkey-tiedosto + Pääsyavaintiedosto All files @@ -6367,25 +6843,27 @@ haluatko korvata sen? Open passkey file - + Avaa pääsyavaintiedosto Cannot import passkey - + Pääsyavainta ei voitu tuoda Cannot import passkey file "%1". Data is missing. - + Pääsyavaintiedostoa "%1" ei voitu tuoda. Tietoja puuttuu. Cannot import passkey file "%1". The following data is missing: %2 - + Pääsyavaintiedostoa ei voida tuoda "%1". +Seuraavat tiedot puuttuvat: +%2 Cannot import passkey file "%1". Private key is missing or malformed. - + Pääsyavaintiedostoa ei voida tuoda "%1". Yksityinen avain puuttuu tai on virheellinen. @@ -6566,10 +7044,6 @@ The following data is missing: Also choose from: Valitse myös: - - Excluded characters: "0", "1", "l", "I", "O", "|", "﹒" - Poissuljetut kirjaimet: "0", "1", "l", "I", "O", "|", "﹒" - Exclude look-alike characters Poissulje samannäköiset merkit @@ -6594,10 +7068,6 @@ The following data is missing: Word Count: Sanamäärä: - - Character Count: - Merkkien lukumäärä: - Word Case: Aakkoslaji: @@ -6610,10 +7080,6 @@ The following data is missing: Add custom wordlist Lisää mukautettu sanalista - - character - merkki - Close Sulje @@ -6720,6 +7186,22 @@ Haluatko ylikirjoittaa sen? Special Characters Erikoismerkit + + passwordLength + salasanan pituus + + + Characters: %1 + Krijaimia: %1 + + + MIXED case + + + + Excluded characters: "0", "1", "l", "I", "O", "|", "﹒", "B", "8", "G", "6" + Pois suljetut merkit: ”0”, ”1”, ”l”, ”I”, ”O”, ”|”, ”﹒”, ”B”, ”8”, ”G”, ”6” + PasswordWidget @@ -6787,6 +7269,21 @@ Haluatko ylikirjoittaa sen? Paina &Tab merkkien välillä + + PreviewEntryAttachmentsDialog + + Preview entry attachment + + + + No preview available + + + + Image format not supported + + + QMessageBox @@ -7465,10 +7962,6 @@ Haluatko ylikirjoittaa sen? Invalid word count %1 Väärä sanamäärä %1 - - The word list is too small (< 1000 items) - Sanalista on liian pieni (< 1000 sanaa) - Title for the entry. Tietueen nimi @@ -7613,10 +8106,6 @@ Haluatko ylikirjoittaa sen? Exit interactive mode. Poistu interaktiivisesta tilasta. - - Format to use when exporting. Available choices are 'xml' or 'csv'. Defaults to 'xml'. - Viennissä käytettävä formaatti. Mahdolliset vaihtoehdot ovat 'xml' tai 'csv'. Oletus on 'xml'. - Exports the content of a database to standard output in the specified format. Vie tietokannan sisällön standardiin tulosteeseen (stdout) halutussa formaatissa. @@ -8205,18 +8694,6 @@ Ydin: %3 %4 file empty tyhjä tiedosto - - malformed string - Viallinen merkkijono - - - missing closing quote - lainausmerkki puuttuu lopusta - - - %1: (row, col) %2,%3 - %1: (rivi, sarake) %2,%3 - AES 256-bit AES 256-bit @@ -8460,11 +8937,12 @@ Ydin: %3 %4 Set the key file for the database. This option is deprecated, use --set-key-file instead. - + Aseta tietokannan avaintiedosto. +Asetus on vanhentunut, käytä sen sijaan "--set-key-file" -määritystä. Databases have been locked. - + Tietokannat on lukittu. Attestation not supported @@ -8476,7 +8954,7 @@ This option is deprecated, use --set-key-file instead. Passkeys request canceled - Passkey-pyyntö peruttiin + Pääsyavainpyyntö peruttiin Invalid user verification @@ -8492,7 +8970,7 @@ This option is deprecated, use --set-key-file instead. Passkeys - Passkeyt + Pääsyavaimet AES initialization failed @@ -8661,13 +9139,89 @@ This option is deprecated, use --set-key-file instead. Pikanäppäimet - Unsupported KDF type, cannot decrypt json file + Unknown passkeys error + Tuntematon pääsyavainvirhe + + + Invalid KDF iterations, cannot decrypt json file + Virheellinen KDF-iteraation. JSON-tiedostoa ei voitu purkaa. + + + Unsupported format, ensure your Bitwarden export is password-protected + Tiedostomuoto ei ole tuettu. Varmista, että Bitwarden-tiedostosi on salasanasuojattu. + + + Only PBKDF and Argon2 are supported, cannot decrypt json file + Vain PBKDF ja Argon2 ovat tuettuja. JSON-tiedostoa ei voitu purkaa. + + + Reset Shortcuts + Nollaa pikanäppäimet + + + Double click an action to change its shortcut + Tuplaklikkaa toimintoa vaihtaaksesi sen pikanäppäintä + + + Filter... + Suodata... + + + Shortcut Conflict + Pikanäppäimen ristiriita + + + Shortcut %1 conflicts with '%2'. Overwrite shortcut? + Pikanäppäin %1 on ristiriidassa '%2' kanssa. Ylikirjoita pikanäppäin? + + + Cannot generate valid passphrases because the wordlist is too short + Salalausetta ei voitu luoda, sillä sanalista on liian lyhyt. + + + Encrypted files are not supported. + Salattuja tiedostoja ei tueta. + + + Proton Pass Import + Proton Pass -tuonti + + + Delete plugin data? + Poista liitännäistiedot? + + + Delete plugin data from Entry(s)? + Poista liitännäistiedot tietueesta?Poista liitännäistiedot tietueista? + + + Passkey + Pääsyavain + + + Format to use when exporting. Available choices are 'xml', 'csv' or 'html'. Defaults to 'xml'. - Unknown passkeys error + start minimized to the system tray + + malformed string, possible unescaped delimiter + + + + missing closing delimiter + + + + %1, row: %2, column: %3 + + + + Tags + Tagit + QtIOCompressor @@ -8703,6 +9257,37 @@ This option is deprecated, use --set-key-file instead. Sisäinen zlib-virhe: + + RemoteHandler + + Command `%1` did not finish in time. Process was killed. + Komento '%1' ei suoritutunut määritetyssä ajassa. Prosessi tuhottiin. + + + Failed to upload merged database. Command `%1` did not finish in time. Process was killed. + Yhdistetyn tietokannan lähetys epäonnistui. Komento '%1' ei suoriutunut määritetyssä ajassa. Prosessi tuhottin. + + + Invalid download parameters provided. + Väärät latausparametrit. + + + Command `%1` failed to download database. + Komento '%1' epäonnistui tietokannan lataamisessa. + + + Invalid database pointer or upload parameters provided. + Virheellinen tietokannan osoitin, tai lähetyksen parametrit. + + + Command `%1` exited with status code: %2 + Komento '%1' suoriutui paluuarvolla: %2 + + + Failed to upload merged database. Command `%1` exited with status code: %2 + Yhdistetyn tietokannan lähetys epäonnistui. Komento '%1' loppui paluuarvolla: %2 + + ReportsWidgetBrowserStatistics @@ -8769,6 +9354,10 @@ This option is deprecated, use --set-key-file instead. Exclude from reports Poissulje raporteista + + Expire Entry(s)… + + Only show entries that have a URL Näytä vain URL-osoitteen sisältävät tietueet @@ -8785,36 +9374,33 @@ This option is deprecated, use --set-key-file instead. (Expired) (erääntynyt) + + Delete plugin data from Entry(s)… + Poista liitännäistiedot tietueesta…Poista liitännäistiedot tietueista… + ReportsWidgetHealthcheck - Hover over reason to show additional details. Double-click entries to edit. - Siirrä kursori syyn päälle nähdäksesi lisätietoja. Tuplaklikkaa tietueita muokataksesi niitä. + Show expired entries + Näytä erääntyneet tietueet - Bad - Password quality - Paha + (Expired) + (erääntynyt) + + + Hover over reason to show additional details. Double-click entries to edit. + Siirrä kursori syyn päälle nähdäksesi lisätietoja. Tuplaklikkaa tietueita muokataksesi niitä. Bad — password must be changed Paha - salasana on vaihdettava - - Poor - Password quality - Huono - Poor — password should be changed Heikko - salasana on vaihdettava - - Weak - Password quality - Heikko - Weak — consider changing the password Heikohko - salasana on vaihdettava @@ -8863,18 +9449,14 @@ This option is deprecated, use --set-key-file instead. Exclude from reports Poissulje raporteista - - Show expired entries - Näytä erääntyneet tietueet + + Expire Entry(s)… + Show entries that have been excluded from reports Näytä tietueet, joita ei sisällytetä raportteihin. - - (Expired) - (erääntynyt) - ReportsWidgetHibp @@ -8970,6 +9552,10 @@ This option is deprecated, use --set-key-file instead. Exclude from reports Poissulje raporteista + + Expire Entry(s)… + + ReportsWidgetPasskeys @@ -9027,15 +9613,15 @@ This option is deprecated, use --set-key-file instead. The passkey file will be vulnerable to theft and unauthorized use, if left unsecured. Are you sure you want to continue? - + Pääsyavaintiedosto on altis varkauksille ja väärinkäyttöön, jos sitä ei suojata. Oletko varma, että haluat jatkaa? Please wait, list of entries with passkeys is being updated… - + Odota kun pääsyavaintietueiden lista päivittyy... No entries with passkeys. - + Pääsyavaimia sisältäviä tietueita ei ole. @@ -9211,6 +9797,14 @@ This option is deprecated, use --set-key-file instead. No agent running, cannot list identities. Agentti ei ole päällä, tunnisteita ei voi listata. + + Failed to remove all SSH identities from agent. + + + + All SSH identities removed from agent. + + SearchHelpWidget @@ -9385,11 +9979,11 @@ This option is deprecated, use --set-key-file instead. <html><head/><body><p>This setting does not override disabling recycle bin prompts </p></body></html> - + <html><head/><body><p>Tämä asetus ei ylikirjoita roskakorin ilmoitusten poistamista</p></body></html> <html><head/><body><p>This improves compatibility with certain applications which search for password without unlocking the database first.</p><p>But enabling this may also crash the client if the database can not be unlocked within a certain timeout. (Usually 25s, but may be a different value set in applications.) </p></body></html> - + <html><head/><body><p>Tämä parantaa yhteensopivuutta joidenkin ohjelmien kanssa, jotka etsivät salasanoja ilman tietokannan avaamista etukäteen.</p><p>Tämän päälle laittaminen saattaa myös kaataa asiakkaan, mikäli tietokantaa ei voitu avata tiettyyn aikaan mennessä. (Yleensä 25 sekuntia, mutta arvo voi vaihdella ohjelmasta riippuen.)</p></body></html> @@ -9496,29 +10090,6 @@ This option is deprecated, use --set-key-file instead. Vie kohteeseen %1 - - ShortcutSettingsWidget - - Double click an action to change its shortcut - Tuplaklikkaa toimintoa vaihtaaksesi sen pikanäppäintä - - - Shortcut Conflict - Pikanäppäimen ristiriita - - - Filter... - Suodata... - - - Shortcut %1 conflicts with '%2'. Overwrite shortcut? - Pikanäppäin %1 on ristiriidassa '%2' kanssa. Ylikirjoita pikanäppäin? - - - Reset Shortcuts - Nollaa pikanäppäimet - - TagModel @@ -9807,14 +10378,18 @@ Esimerkiksi: JBSWY3DPEHPK3PXP No hardware keys detected Laiteavaimia ei havaittu - - <p>If you own a <a href="https://www.yubico.com/">YubiKey</a> or <a href="https://onlykey.io">OnlyKey</a>, you can use it for additional security.</p><p>The key requires one of its slots to be programmed as <a href="https://docs.yubico.com/yesdk/users-manual/application-otp/challenge-response.html">HMAC-SHA1 Challenge-Response</a>.</p> - <p>Jos omistat <a href="https://www.yubico.com/">YubiKeyn</a>tai <a href="https://onlykey.io">OnlyKeyn</a>, voit käyttää sitä lisäturvakeinona.</p><p>Avain vaatii yhden paikan asettamista <a href="https://docs.yubico.com/yesdk/users-manual/application-otp/challenge-response.html">HMAC-SHA1 -haaste-vastaukseksi</a>.</p> - Refresh hardware keys Uudista laiteavaimet + + <p>If you own a <a href="https://www.yubico.com/">YubiKey</a> or <a href="https://onlykey.io">OnlyKey</a>, you can use it for additional security.</p><p>The key requires one of its slots to be programmed with <a href="https://keepassxc.org/docs/#faq-yubikey-howto">Challenge-Response</a>.</p> + <p>Jos sinulla on <a href="https://www.yubico.com/">YubiKey</a> tai <a href="https://onlykey.io">OnlyKey</a>, sitä voi käyttää lisäturvaksi</p><p>Avain vaatii, että yksi sen kentistä ohjelmoidaan <a href="https://keepassxc.org/docs/#faq-yubikey-howto">Challenge-Response</a>-ohjelmalla.</p> + + + Hardware keys found, but no slots are configured + + YubiKeyInterfacePCSC diff --git a/share/translations/keepassxc_fil.ts b/share/translations/keepassxc_fil.ts index 6d8fcb25a..e88a55c8d 100644 --- a/share/translations/keepassxc_fil.ts +++ b/share/translations/keepassxc_fil.ts @@ -217,18 +217,50 @@ You must restart the application to set the new language. Would you like to restart now? You must restart the application to set the new language. Would you like to restart now? - - Reset Settings? - I-reset ang Mga Setting? - - - Are you sure you want to reset all general and security settings to default? - Sigurado ka bang nais mong i-reset ang pangkalahatan at mga setting ng seguridad sa default? - Select backup storage directory Piliin ang direktoryo ng backup na storage + + Confirm Reset + + + + Are you sure you want to reset all settings to default? + + + + Import KeePassXC Settings + + + + Failed to import settings from %1, not a valid settings file. + + + + Export KeePassXC Settings + + + + Small + + + + Normal + + + + Medium + + + + Large + + + + Custom + + ApplicationSettingsWidgetGeneral @@ -280,25 +312,6 @@ Include beta releases when checking for updates Isama ang mga nilabas na beta kapag tumitingin ng mga update - - On database unlock, show entries that - Sa pag-unlock ng database, ipakita ang mga entry na - - - have expired - On database unlock, show entries that... - nag-expire na - - - days - On database unlock, show entries that will expire within %1 days - araw - - - will expire within - On database unlock, show entries that... - ay mawawalan ng bisa sa loob ng - File Management Pamamahala ng File @@ -323,22 +336,10 @@ Backup database file before saving I-backup ang database file bago i-save - - Backup destination - Backup na destinasyon - - - Specifies the database backup file location. Occurrences of "{DB_FILENAME}" are replaced with the filename of the saved database without extension. {TIME:<format>} is replaced with the backup time, see https://doc.qt.io/qt-5/qdatetime.html#toString. <format> defaults to format string "dd_MM_yyyy_hh-mm-ss". - Tinutukoy ang lokasyon ng backup file ng database. Mga pangyayari ng "{DB_FILENAME}" ay pinalitan ng filename ng naka-save na database nang walang extension. {TIME:<format>} ay pinalitan ng oras ng pag-backup, tingnan ang https://doc.qt.io/qt-5/qdatetime.html#toString. <format> default sa pag-format ng string "dd_MM_yyyy_hh-mm-ss". - {DB_FILENAME}.old.kdbx {DB_FILENAME}.old.kdbx - - Choose... - Pumili... - Use alternative saving method (may solve problems with Dropbox, Google Drive, GVFS, etc.) Gumamit ng alternatibong paraan ng pag-save (maaaring malutas ang mga problema sa Dropbox, Google Drive, GVFS, atbp.) @@ -505,6 +506,71 @@ Remember last typed entry for: Tandaan ang huling na-type na entry para sa: + + On database unlock, show entries that will expire within + + + + On database unlock, show entries that will expire within + + + + days + number of days warning for password expiration + araw + + + Destination format: + + + + <html><head/><body><p><span style=" font-weight:600;">{DB_FILENAME}</span> is replaced with the filename of the saved database without extension</p><p><span style=" font-weight:600;">{TIME:&lt;format&gt;}</span> is replaced with the specified time format (default: dd_MM_yyyy_hh-mm-ss)</p><p>See the User Guide for more details</p></body></html> + + + + Choose folder... + + + + Show confirmation before moving entries to recycle bin + + + + Copy data on double clicking field in entry view + + + + Show toolbar + + + + Show the menu bar by pressing the Alt key + + + + Show menubar + + + + Import settings… + + + + Export settings… + + + + Open browser on double clicking URL field in entry view + + + + Font size: + + + + Font size selection + + ApplicationSettingsWidgetSecurity @@ -570,18 +636,6 @@ Hide passwords in the entry preview panel Itago ang mga password sa panel ng preview ng entry - - Hide entry notes by default - Itago ang mga note ng entry bilang default - - - Move entries to recycle bin without confirmation - Ilipat ang mga entry sa recycle bin nang walang kumpirmasyon - - - Enable double click to copy the username/password entry columns - I-enable ang double click para kopyahin ang mga column ng username/password entry - Privacy Privacy @@ -594,6 +648,18 @@ Hide TOTP in the entry preview panel + + Lock databases when switching user + + + + Lock Options + + + + Hide notes in the entry preview panel + + AutoType @@ -641,20 +707,6 @@ Entry does not have attribute for PICKCHARS: %1 Ang entry ay walang attribute para sa PICKCHARS: %1 - - Invalid conversion type: %1 - Invalid na uri ng conversion: %1 - - - Invalid conversion syntax: %1 - Invalid na conversion syntax: %1 - - - Invalid regular expression syntax %1 -%2 - Invalid na syntax ng regular na expression na %1 -%2 - Invalid placeholder: %1 Invalid na placeholder: %1 @@ -1022,10 +1074,6 @@ Do you want to overwrite the passkey in %1 - %2? General Pangkalahatan - - Browsers installed as snaps are currently not supported. - Ang mga browser na naka-install bilang mga snap ay kasalukuyang hindi suportado. - Enable integration for these browsers: I-enable ang integration para sa mga browser na ito: @@ -1197,18 +1245,6 @@ Do you want to overwrite the passkey in %1 - %2? Custom extension ID Custom na extension ID - - Due to Snap sandboxing, you must run a script to enable browser integration.<br />You can obtain this script from %1 - Dahil sa Snap sandboxing, dapat kang mag-run ng script para i-enable ang pag-integrate ng browser.<br />Makukuha mo ang script na ito mula sa %1 - - - KeePassXC-Browser is needed for the browser integration to work. <br />Download it for %1 and %2 and %3. %4 - Kailangan ang KeePassXC-Browser para gumana ang browser integration. <br />I-download ito para sa %1 at %2 at %3. %4 - - - Please see special instructions for browser extension use below - Pakitingnan ang mga espesyal na tagubilin para sa paggamit ng extension ng browser sa ibaba - Executable Files Mga Executable na File @@ -1257,6 +1293,14 @@ Do you want to overwrite the passkey in %1 - %2? Allow using localhost with passkeys + + KeePassXC-Browser is needed for the browser integration to work. <br />Download it for %1 and %2 and %3. + + + + Browsers installed using Snap or Flatpak are not supported with exception to Firefox installed using Snap. + + CloneDialog @@ -1399,6 +1443,19 @@ Do you want to overwrite the passkey in %1 - %2? Imported from CSV file: %1 + + No Title Selected + + + + No title column was selected, entries will be hard to tell apart. +Are you sure you want to import? + + + + Tags + Mga tag + CsvParserModel @@ -1462,6 +1519,14 @@ Backup database na matatagpuan sa %2 Recycle Bin Recycle Bin + + Database file read error. + + + + No file path was provided. + + DatabaseOpenDialog @@ -1610,14 +1675,6 @@ Para maiwasan ang paglabas ng error na ito, dapat kang pumunta sa "Settings <p>In addition to a password, you can use a secret file to enhance the security of your database. This file can be generated in your database's security settings.</p><p>This is <strong>not</strong> your *.kdbx database file!</p> - - Click to add a key file. - - - - <a href="#" style="text-decoration: underline">I have a key file</a> - - Use hardware key [Serial: %1] @@ -1650,6 +1707,18 @@ Are you sure you want to continue with this file?. Refresh Hardware Keys + + Click to add a key file. + + + + <a href="#" style="text-decoration: underline">I have a key file</a> + + + + Hardware keys found, but no slots are configured. + + DatabaseSettingWidgetMetaData @@ -1684,6 +1753,22 @@ Are you sure you want to continue with this file?. Maintenance Maintenance + + KeeShare + KeeShare + + + Secret Service Integration + Secret Service Integration + + + Remote Sync + + + + Database Settings: %1 + + DatabaseSettingsWidgetBrowser @@ -1855,11 +1940,11 @@ Sigurado ka bang gusto mong magpatuloy nang walang password? Mahinang password - You must enter a stronger password to protect your database. + This is a weak password! For better protection of your secrets, you should choose a stronger password. - This is a weak password! For better protection of your secrets, you should choose a stronger password. + The provided password does not meet the minimum quality requirement. @@ -2163,6 +2248,50 @@ na-delete mula sa database. Autosave delay since last change checkbox + + Public Database Metadata + + + + Warning: the following settings are not encrypted. + + + + Display name: + + + + Publically visible display name used on the unlock dialog + + + + Database public display name + + + + Display color: + + + + Publically visible color used on the unlock dialog + + + + Database public display color chooser + + + + Clear + I-clear + + + Display icon: + + + + Select Database Icon + + DatabaseSettingsWidgetKeeShare @@ -2258,6 +2387,129 @@ na-delete mula sa database. Field ng paglalarawan ng database + + DatabaseSettingsWidgetRemote + + Sync Commands + + + + Remove + Alisin + + + Command Settings + + + + Name + Pangalan + + + Save + I-save + + + Download + + + + Command: + + + + Download command field + + + + e.g.: "sftp user@hostname" or "scp user@hostname:DatabaseOnRemote.kdbx {TEMP_DATABASE}" + + + + Input: + + + + Download input field + + + + Upload + + + + Upload command field + + + + e.g.: "sftp user@hostname" or "scp {TEMP_DATABASE} user@hostname:DatabaseOnRemote.kdbx" + + + + Upload input field + + + + Name cannot be empty. + + + + Test + + + + Download command cannot be empty. + + + + Download failed with error: %1 + + + + Download finished, but file %1 could not be found. + + + + Download successful. + + + + Save Remote Settings + + + + You have unsaved changes. Do you want to save them? + + + + e.g.: +get DatabaseOnRemote.kdbx {TEMP_DATABASE} +exit +--- +{TEMP_DATABASE} is used as placeholder to store the database in a temporary location +The command has to exit. In case of `sftp` as last command `exit` has to be sent + + + + + e.g.: +put {TEMP_DATABASE} DatabaseOnRemote.kdbx +exit +--- +{TEMP_DATABASE} is used as placeholder to store the database in a temporary location +The command has to exit. In case of `sftp` as last command `exit` has to be sent + + + + + Timeout: + + + + seconds + segundo + + DatabaseTabWidget @@ -2331,6 +2583,11 @@ Tiyak na bug ito, mangyaring i-ulat sa mga developer. Database tab name modifier %1 [Naka-lock] + + %1 [Temporary] + Database tab name modifier + + DatabaseWidget @@ -2454,26 +2711,6 @@ I-save ang mga pagbabago? File has changed Nagbago ang file - - The database file has changed. Do you want to load the changes? - Nagbago ang database file. Gusto mo bang i-load ang mga pagbabago? - - - Merge Request - Pagsamahin ang Kahilingan - - - The database file has changed and you have unsaved changes. -Do you want to merge your changes? - Ang file ng database ay nabago at mayroon kang mga hindi na-save na mga pagbabago. -Gusto mo bang pagsamahin ang mga binago mo? - - - Could not open the new database file while attempting to autoreload. -Error: %1 - Hindi mabuksan ang bagong database file habang sinusubukang i-autoreload. -Error: %1 - Disable safe saves? I-disable ang ligtas na pag-save? @@ -2525,6 +2762,86 @@ I-disable ang safe save at subukang muli? Database tab name modifier %1 [Bagong Database] + + Remote Sync did not contain any download or upload commands. + + + + Remote sync '%1' completed successfully! + + + + Remote sync '%1' failed: %2 + + + + Error while saving database %1: %2 + + + + Downloading... + + + + Uploading... + + + + Syncing... + + + + Remove passkey from entry + + + + Do you want to remove the passkey from this entry? + + + + The database file "%1" was modified externally + + + + Do you want to load the changes? + + + + Reload database + + + + Reloading database… + + + + Reload canceled + + + + Reload successful + + + + Reload pending user action… + + + + The database file "%1" was modified externally.<br>How would you like to proceed?<br><br>Merge all changes<br>Ignore the changes on disk until save<br>Discard unsaved changes + + + + The database file "%1" was modified externally.<br>How would you like to proceed?<br><br>Merge all changes then save<br>Overwrite the changes on disk<br>Discard unsaved changes + + + + Database file overwritten. + + + + Database file on disk cannot be unlocked with current credentials.<br>Enter new credentials and/or present hardware key to continue. + + EditEntryWidget @@ -2576,10 +2893,6 @@ I-disable ang safe save at subukang muli? n/a n/a - - (encrypted) - (naka-encrypt) - Select private key Pumili ng private key @@ -2682,6 +2995,10 @@ Gusto mo bang itama ito? %n year(s) %n taon%n (mga)taon + + Failed to decrypt SSH key, ensure password is correct. + + EditEntryWidgetAdvanced @@ -2853,18 +3170,10 @@ Gusto mo bang itama ito? Skip Auto-Submit for this entry Laktawan ang Auto-Submit para sa entry na ito: - - Only send this setting to the browser for HTTP Auth dialogs. If enabled, normal login forms will not show this entry for selection. - Ipadala lamang ang setting na ito sa browser para sa mga dialog ng HTTP Auth. Kung na-enable, hindi ipapakita ng mga normal na form sa pag-log in ang entry na ito para sa pagpili. - Use this entry only with HTTP Basic Auth Gamitin lamang ang entry na ito sa HTTP Basic Auth - - Do not send this setting to the browser for HTTP Auth dialogs. If enabled, HTTP Auth dialogs will not show this entry for selection. - Huwag ipadala ang setting na ito sa browser para sa mga dialog ng HTTP Auth. Kung naka-enable, hindi ipapakita ng mga dialog ng HTTP Auth ang entry na ito para sa pagpili. - Do not use this entry with HTTP Basic Auth Huwag gamitin ang entry na ito sa HTTP Basic Auth @@ -2889,6 +3198,14 @@ Gusto mo bang itama ito? Additional URLs + + Only send this entry to the browser for HTTP Auth dialogs. If enabled, normal login forms will not show this entry for selection. + + + + Do not send this entry to the browser for HTTP Auth dialogs. If enabled, HTTP Auth dialogs will not show this entry for selection. + + EditEntryWidgetHistory @@ -3111,6 +3428,10 @@ Gusto mo bang itama ito? seconds segundo + + Clear agent + + EditGroupWidget @@ -3553,6 +3874,24 @@ Maaari itong maging sanhi ng hindi paggana ng mga apektadong plugin.%1 - Clone %1 - Clone + + Passkey + + + + Invalid conversion type: %1 + Invalid na uri ng conversion: %1 + + + Invalid conversion syntax: %1 + Invalid na conversion syntax: %1 + + + Invalid regular expression syntax %1 +%2 + Invalid na syntax ng regular na expression na %1 +%2 + EntryAttachments @@ -3561,6 +3900,21 @@ Maaari itong maging sanhi ng hindi paggana ng mga apektadong plugin.Hindi mabuksan ang file na "%1" + + EntryAttachmentsDialog + + Form + Form + + + File name + + + + File contents... + + + EntryAttachmentsModel @@ -3598,14 +3952,6 @@ Maaari itong maging sanhi ng hindi paggana ng mga apektadong plugin.Remove Alisin - - Rename selected attachment - Pangalanan muli ang napiling attachment - - - Rename - Pangalanan muli - Open selected attachment Buksan ang napiling attachment @@ -3721,6 +4067,18 @@ Would you like to overwrite the existing attachment? Umiiral na ang attachment na "%1". Gusto mo bang i-overwrite ang kasalukuyang attachment? + + New + + + + Preview + Preview + + + Failed to preview an attachment: Attachment not found + + EntryAttributesModel @@ -3919,6 +4277,10 @@ Gusto mo bang i-overwrite ang kasalukuyang attachment? Background Color + + Group Path + + EntryPreviewWidget @@ -4314,6 +4676,14 @@ Puwede mong i-enable ang icon service ng website ng DuckDuckGo sa seksyon ng seg Url + + Could not load key file. + + + + Could not open remote database. Password or key file may be incorrect. + + ImportWizardPageSelect @@ -4417,6 +4787,44 @@ Puwede mong i-enable ang icon service ng website ng DuckDuckGo sa seksyon ng seg KeePass1 Database + + Proton Pass (.json) + + + + Proton Pass JSON Export + + + + Temporary Database + + + + Command: + + + + e.g.: "sftp user@hostname" or "scp user@hostname:DatabaseOnRemote.kdbx {TEMP_DATABASE}" + + + + Input: + + + + e.g.: +get DatabaseOnRemote.kdbx {TEMP_DATABASE} +exit +--- +{TEMP_DATABASE} is used as placeholder to store the database in a temporary location +The command has to exit. In case of `sftp` as last commend `exit` has to be sent + + + + + Remote Database (.kdbx) + + KMessageWidget @@ -5557,12 +5965,6 @@ Ang bersyon na ito ay hindi para sa paggamit ng produksyon. Expect some bugs and minor issues, this version is meant for testing purposes. TANDAAN: Gumagamit ka ng paunang labas na bersyon ng KeePassXC. Asahan ang ilang mga bug at maliliit na isyu, ang bersyon na ito ay para sa mga pagsubok na layunin. - - - WARNING: Your Qt version may cause KeePassXC to crash with an On-Screen Keyboard. -We recommend you use the AppImage available on our downloads page. - BABALA: Ang bersyon ng Qt mo ay maaaring magdulot ng pag-crash ng KeePassXC gamit ang On-Screen Keyboard. -Inirerekomenda naming gamitin mo ang AppImage na available sa aming pahina ng mga pag-download. No Tags @@ -5636,6 +6038,10 @@ Inirerekomenda naming gamitin mo ang AppImage na available sa aming pahina ng mg Import Passkey + + Remote S&ync… + + Quit Application @@ -5740,6 +6146,10 @@ Inirerekomenda naming gamitin mo ang AppImage na available sa aming pahina ng mg Show Password Generator + + Remove Passkey From Entry + + Perform Auto-Type: {USERNAME} @@ -5884,6 +6294,34 @@ Inirerekomenda naming gamitin mo ang AppImage na available sa aming pahina ng mg Toggle Allow Screen Capture + + Show Group Panel + + + + Toggle Show Group Panel + + + + Setup Remote Sync… + + + + Password Generator + + + + E&xpire Entry… + + + + Clear SSH Agent + + + + Clear all identities in ssh-agent + + ManageDatabase @@ -6034,6 +6472,25 @@ Inirerekomenda naming gamitin mo ang AppImage na available sa aming pahina ng mg Pakipunan ang display name at isang opsyonal na paglalarawan para sa iyong bagong database: + + NewEntryAttachmentsDialog + + Attachment name cannot be empty + + + + Attachment with the same name already exists + + + + Save attachment + + + + New entry attachment + + + NixUtils @@ -6221,6 +6678,10 @@ Inirerekomenda naming gamitin mo ang AppImage na available sa aming pahina ng mg Unexpected EOF when writing private key Hindi inaasahang EOF kapag nagsusulat ng private key + + (encrypted) + (naka-encrypt) + OpenSSHKeyGenDialog @@ -6571,10 +7032,6 @@ The following data is missing: Also choose from: Gayundin, pumili mula sa: - - Excluded characters: "0", "1", "l", "I", "O", "|", "﹒" - Mga ibinukod na character: "0", "1", "l", "I", "O", "|", "﹒" - Exclude look-alike characters Ibukod ang mga halos katulad na karakter @@ -6599,10 +7056,6 @@ The following data is missing: Word Count: Bilang ng Salita: - - Character Count: - Bilang ng Character: - Word Case: Word Case: @@ -6615,10 +7068,6 @@ The following data is missing: Add custom wordlist Magdagdag ng custom wordlist - - character - character - Close I-close @@ -6725,6 +7174,22 @@ Gusto mo bang i-overwrite ito? Special Characters Mga Espesyal na Character + + passwordLength + + + + Characters: %1 + + + + MIXED case + + + + Excluded characters: "0", "1", "l", "I", "O", "|", "﹒", "B", "8", "G", "6" + + PasswordWidget @@ -6792,6 +7257,21 @@ Gusto mo bang i-overwrite ito? Pindutin ang &Tab sa pagitan ng mga character + + PreviewEntryAttachmentsDialog + + Preview entry attachment + + + + No preview available + + + + Image format not supported + + + QMessageBox @@ -7470,10 +7950,6 @@ Gusto mo bang i-overwrite ito? Invalid word count %1 Invalid na word count na %1 - - The word list is too small (< 1000 items) - Masyadong maliit ang listahan ng salitang (< 1000 item) - Title for the entry. Pamagat para sa entry @@ -7618,10 +8094,6 @@ Gusto mo bang i-overwrite ito? Exit interactive mode. Lumabas sa interactive mode. - - Format to use when exporting. Available choices are 'xml' or 'csv'. Defaults to 'xml'. - Format na gagamitin kapag nag-e-export. Ang mga available na pagpipilian ay 'xml' o 'csv'. Default sa 'xml'. - Exports the content of a database to standard output in the specified format. Nai-export na ang nilalaman ng isang database sa karaniwang output sa tinukoy na format. @@ -8210,18 +8682,6 @@ Kernel: %3 %4 file empty walang lamang file - - malformed string - malformed na string - - - missing closing quote - nawawalang closing quote - - - %1: (row, col) %2,%3 - %1: (row, col) %2,%3 - AES 256-bit AES 256-bit @@ -8666,13 +9126,89 @@ This option is deprecated, use --set-key-file instead. - Unsupported KDF type, cannot decrypt json file + Unknown passkeys error - Unknown passkeys error + Invalid KDF iterations, cannot decrypt json file + + Unsupported format, ensure your Bitwarden export is password-protected + + + + Only PBKDF and Argon2 are supported, cannot decrypt json file + + + + Reset Shortcuts + + + + Double click an action to change its shortcut + + + + Filter... + + + + Shortcut Conflict + + + + Shortcut %1 conflicts with '%2'. Overwrite shortcut? + + + + Cannot generate valid passphrases because the wordlist is too short + + + + Encrypted files are not supported. + + + + Proton Pass Import + + + + Delete plugin data? + I-delete ang data ng plugin? + + + Delete plugin data from Entry(s)? + + + + Passkey + + + + Format to use when exporting. Available choices are 'xml', 'csv' or 'html'. Defaults to 'xml'. + + + + start minimized to the system tray + + + + malformed string, possible unescaped delimiter + + + + missing closing delimiter + + + + %1, row: %2, column: %3 + + + + Tags + Mga tag + QtIOCompressor @@ -8708,6 +9244,37 @@ This option is deprecated, use --set-key-file instead. Panloob na zlib na error: + + RemoteHandler + + Command `%1` did not finish in time. Process was killed. + + + + Failed to upload merged database. Command `%1` did not finish in time. Process was killed. + + + + Invalid download parameters provided. + + + + Command `%1` failed to download database. + + + + Invalid database pointer or upload parameters provided. + + + + Command `%1` exited with status code: %2 + + + + Failed to upload merged database. Command `%1` exited with status code: %2 + + + ReportsWidgetBrowserStatistics @@ -8774,6 +9341,10 @@ This option is deprecated, use --set-key-file instead. Exclude from reports Ibukod mula sa mga ulat + + Expire Entry(s)… + + Only show entries that have a URL @@ -8790,36 +9361,33 @@ This option is deprecated, use --set-key-file instead. (Expired) + + Delete plugin data from Entry(s)… + + ReportsWidgetHealthcheck - Hover over reason to show additional details. Double-click entries to edit. - Mag-hover sa itaas para makita ng mga karagdagang detalye. I-double click ang mga entry para i-edit. + Show expired entries + - Bad - Password quality - Hindi maganda + (Expired) + + + + Hover over reason to show additional details. Double-click entries to edit. + Mag-hover sa itaas para makita ng mga karagdagang detalye. I-double click ang mga entry para i-edit. Bad — password must be changed Hindi maganda — dapat palitan ang password - - Poor - Password quality - Mahina - Poor — password should be changed Mahina — dapat palitan ang password - - Weak - Password quality - Mahina - Weak — consider changing the password Mahina — isaalang-alang ang pagpapalit ng password @@ -8868,18 +9436,14 @@ This option is deprecated, use --set-key-file instead. Exclude from reports Ibukod mula sa mga ulat - - Show expired entries - + + Expire Entry(s)… + Show entries that have been excluded from reports - - (Expired) - - ReportsWidgetHibp @@ -8975,6 +9539,10 @@ This option is deprecated, use --set-key-file instead. Exclude from reports Ibukod mula sa mga ulat + + Expire Entry(s)… + + ReportsWidgetPasskeys @@ -9216,6 +9784,14 @@ This option is deprecated, use --set-key-file instead. No agent running, cannot list identities. Walang gumaganang ahente, hindi makakapaglista ng mga pagkakakilanlan. + + Failed to remove all SSH identities from agent. + + + + All SSH identities removed from agent. + + SearchHelpWidget @@ -9501,29 +10077,6 @@ This option is deprecated, use --set-key-file instead. I-export sa %1 - - ShortcutSettingsWidget - - Double click an action to change its shortcut - - - - Shortcut Conflict - - - - Filter... - - - - Shortcut %1 conflicts with '%2'. Overwrite shortcut? - - - - Reset Shortcuts - - - TagModel @@ -9814,11 +10367,15 @@ Halimbawa: JBSWY3DPEHPK3PXP Walang nakitang hardware key - <p>If you own a <a href="https://www.yubico.com/">YubiKey</a> or <a href="https://onlykey.io">OnlyKey</a>, you can use it for additional security.</p><p>The key requires one of its slots to be programmed as <a href="https://docs.yubico.com/yesdk/users-manual/application-otp/challenge-response.html">HMAC-SHA1 Challenge-Response</a>.</p> + Refresh hardware keys - Refresh hardware keys + <p>If you own a <a href="https://www.yubico.com/">YubiKey</a> or <a href="https://onlykey.io">OnlyKey</a>, you can use it for additional security.</p><p>The key requires one of its slots to be programmed with <a href="https://keepassxc.org/docs/#faq-yubikey-howto">Challenge-Response</a>.</p> + + + + Hardware keys found, but no slots are configured diff --git a/share/translations/keepassxc_fr.ts b/share/translations/keepassxc_fr.ts index 4ea93c893..d809f8d39 100644 --- a/share/translations/keepassxc_fr.ts +++ b/share/translations/keepassxc_fr.ts @@ -171,7 +171,7 @@ This setting cannot be enabled when minimize on unlock is enabled. - Ce paramètre ne peut pas être activé lorsque l’option Réduire au déverrouillage est activée. + Ce paramètre ne peut pas être activé si l’option Réduire au déverrouillage est activée. Access error for config file %1 @@ -217,18 +217,50 @@ You must restart the application to set the new language. Would you like to restart now? Pour appliquer la nouvelle langue, vous devez redémarrer l’application. Voulez-vous la démarrer maintenant ? - - Reset Settings? - Réinitialiser les paramètres ? - - - Are you sure you want to reset all general and security settings to default? - Voulez-vous vraiment réinitialiser tous les paramètres généraux et de sécurité à leur valeur par défaut ? - Select backup storage directory Sélectionner le dossier de sauvegarde + + Confirm Reset + Confirmez la remise à zéro + + + Are you sure you want to reset all settings to default? + Etes-vous sûr que vous voulez rétablir la valeur par défault de tous les réglages? + + + Import KeePassXC Settings + Importation des réglages de KeePassXC + + + Failed to import settings from %1, not a valid settings file. + Impossible d'importer les réglages, %1 n'est pas fichier de réglages valide. + + + Export KeePassXC Settings + Exporter les réglages de KeePassXC + + + Small + Petite + + + Normal + Normale + + + Medium + Moyenne + + + Large + Grande + + + Custom + Personnalisée + ApplicationSettingsWidgetGeneral @@ -280,25 +312,6 @@ Include beta releases when checking for updates Inclure les versions bêta lors de la vérification de la présence de mises à jour - - On database unlock, show entries that - Lors du déverrouillage d’une base de données, montrer les entrées qui - - - have expired - On database unlock, show entries that... - ont expiré - - - days - On database unlock, show entries that will expire within %1 days - jours - - - will expire within - On database unlock, show entries that... - expireront dans - File Management Gestion des fichiers @@ -323,22 +336,10 @@ Backup database file before saving Sauvegarder le fichier de la base de données avant d’enregistrer - - Backup destination - Destination de sauvegarde - - - Specifies the database backup file location. Occurrences of "{DB_FILENAME}" are replaced with the filename of the saved database without extension. {TIME:<format>} is replaced with the backup time, see https://doc.qt.io/qt-5/qdatetime.html#toString. <format> defaults to format string "dd_MM_yyyy_hh-mm-ss". - Spécifie l’emplacement du fichier de sauvegarde de la base de données. Les occurrences de « {DB_FILENAME} » sont remplacées par le nom de fichier de la base de données sauvegardée sans extension. {TIME:<format>} est remplacé par l’heure de sauvegarde (consulter https://doc.qt.io/qt-5/qdatetime.html#toString). Par défaut, <format>utilise par défaut le format « dd_MM_yyyy_hh-mm-ss ». - {DB_FILENAME}.old.kdbx {DB_FILENAME}.ancienne.kdbx - - Choose... - Choisir… - Use alternative saving method (may solve problems with Dropbox, Google Drive, GVFS, etc.) Utiliser une méthode d’enregistrement de remplacement (peut résoudre des problèmes avec Dropbox, Google Drive, GVFS, etc.). @@ -418,7 +419,7 @@ Show passwords in color - Montrer les mots de passe en couleur + Afficher les mots de passe en couleur Use monospaced font for notes @@ -505,6 +506,71 @@ Remember last typed entry for: Mémoriser la dernière entrée saisie pendant : + + On database unlock, show entries that will expire within + Lors du déverrouillage d’une base de données, montrer les entrées qui vont expirer dans + + + On database unlock, show entries that will expire within + Lors du déverrouillage d’une base de données, montrer les entrées qui vont expirer dans + + + days + number of days warning for password expiration + jours + + + Destination format: + Format de destination : + + + <html><head/><body><p><span style=" font-weight:600;">{DB_FILENAME}</span> is replaced with the filename of the saved database without extension</p><p><span style=" font-weight:600;">{TIME:&lt;format&gt;}</span> is replaced with the specified time format (default: dd_MM_yyyy_hh-mm-ss)</p><p>See the User Guide for more details</p></body></html> + <html><head/><body><p><span style=" font-weight:600;">{DB_FILENAME}</span> est remplacé par le nom de fichier de la base de données sauvegardée sans extension</p><p><span style=" font-weight:600;">{TIME:&lt;format&gt;}</span> est remplacé par le format de temps spécifié (default: dd_MM_yyyy_hh-mm-ss)</p><p>Voir le Guide Utilisateur pour plus de détails</p></body></html> + + + Choose folder... + Choisissez le répertoire... + + + Show confirmation before moving entries to recycle bin + Afficher une confirmation avant de déplacer les entrées dans la corbeille + + + Copy data on double clicking field in entry view + Copier les données en double-cliquant sur le champ de l'entrée affichée + + + Show toolbar + Afficher la barre d'outils + + + Show the menu bar by pressing the Alt key + Afficher la barre des menus en pressant la touche Alt + + + Show menubar + Afficher la barre de menus + + + Import settings… + Importer les réglages... + + + Export settings… + Exporter les réglages... + + + Open browser on double clicking URL field in entry view + Ouvrir le navigateur en double-cliquant sur le champ URL de l'entrée affichée + + + Font size: + Taille de la police : + + + Font size selection + Sélection de la taille de police + ApplicationSettingsWidgetSecurity @@ -570,18 +636,6 @@ Hide passwords in the entry preview panel Cacher les mots de passe dans le panneau de prévisualisation des entrées - - Hide entry notes by default - Par défaut, cacher les notes des entrées - - - Move entries to recycle bin without confirmation - Déplacer les entrées vers la corbeille sans confirmation - - - Enable double click to copy the username/password entry columns - Activer le double-clic pour copier le nom d’utilisateur et le mot de passe des colonnes d’entrées - Privacy Confidentialité @@ -594,6 +648,18 @@ Hide TOTP in the entry preview panel Cacher le TOTP dans le panneau d’aperçu des entrées + + Lock databases when switching user + Verrouiller les bases de données lors d’un changement d’utilisateur + + + Lock Options + Options de Verrouillage + + + Hide notes in the entry preview panel + Cacher les notes dans le panneau d'aperçu des entrées + AutoType @@ -641,20 +707,6 @@ Entry does not have attribute for PICKCHARS: %1 L'entrée n'a pas d'attribut pour PICKCHARS : %1 - - Invalid conversion type: %1 - Le type de conversion est invalide : %1 - - - Invalid conversion syntax: %1 - La syntaxe de conversion est invalide : %1 - - - Invalid regular expression syntax %1 -%2 - La syntaxe de l’expression rationnelle est invalide %1 -%2 - Invalid placeholder: %1 L’espace réservé est invalide : %1 @@ -714,7 +766,7 @@ Trying to send invalid keyboard symbol. - + Tentative d'envoi d'un caractère de clavier non reconnu. @@ -887,24 +939,25 @@ Veuillez sélectionner la base de données souhaitée pour enregistrer les ident Add to existing entry - + Ajout d'une entrée existante Existing passkey found. Do you want to register a new passkey for: - + Clé d'accès existante trouvée. +Voulez-vous enregistrer la nouvelle clé pour : Select the existing passkey and press Update to replace it. - + Sélectionnez la clé d'accès existante puis cliquez sur Mettre à jour pour la remplacer. Authenticate passkey credentials for: - + Authentifier les identifiants de la clé d'accès pour : Do you want to register a passkey for: - + Voulez-vous enregistrer la clé d'accès pour : @@ -981,7 +1034,7 @@ Voulez-vous la supprimer ? Passkey - + Clé d'accès KeePassXC - Passkey credentials @@ -989,16 +1042,16 @@ Voulez-vous la supprimer ? Register a new passkey to this entry: - + Enregistrer la nouvelle clé d'accès pour cette entrée : KeePassXC - Update passkey - + KeePassXC - Mise à jour de la clé d'accès Entry already has a passkey. Do you want to overwrite the passkey in %1 - %2? - + Cette entrée a déjà une clé d'accès. Remplacer la clé dans %1 - %2 ? Register @@ -1023,10 +1076,6 @@ Do you want to overwrite the passkey in %1 - %2? General Général - - Browsers installed as snaps are currently not supported. - Les navigateurs installés en tant que snap ne sont pas pris en charge actuellement. - Enable integration for these browsers: Activer l’intégration pour ces navigateurs : @@ -1198,18 +1247,6 @@ Do you want to overwrite the passkey in %1 - %2? Custom extension ID ID d’extension personnalisé - - Due to Snap sandboxing, you must run a script to enable browser integration.<br />You can obtain this script from %1 - En raison du bac à sable de Snap, vous devez exécuter un script afin d’activer l’intégration aux navigateurs.<br />Vous pouvez obtenir ce script sur %1 - - - KeePassXC-Browser is needed for the browser integration to work. <br />Download it for %1 and %2 and %3. %4 - KeePassXC-Browser est nécessaire pour que l’intégration aux navigateurs fonctionne. <br />Téléchargez-la pour %1, %2 et %3. %4 - - - Please see special instructions for browser extension use below - Veuillez consulter ci-dessous les instructions spéciales de l’extension pour navigateurs - Executable Files Fichiers exécutables @@ -1252,11 +1289,19 @@ Do you want to overwrite the passkey in %1 - %2? Allows using insecure http://localhost with passkeys for testing purposes. - + Autoriser l'utilisation peu sûre de http://localhost avec les clés d'accès à des fins de test ? Allow using localhost with passkeys - + Autoriser l'utilisation de localhost avec les clés d'accès + + + KeePassXC-Browser is needed for the browser integration to work. <br />Download it for %1 and %2 and %3. + KeePassXC-Browser est nécessaire pour que l'intégration avec le navigateur fonctionne. <br />Téléchargez le pour %1 et %2 et %3. + + + Browsers installed using Snap or Flatpak are not supported with exception to Firefox installed using Snap. + Les navigateurs installés à l'aide de Snap ou de Flatpak ne sont pas pris en charge, à l'exception de Firefox installé à l'aide de Snap. @@ -1267,7 +1312,7 @@ Do you want to overwrite the passkey in %1 - %2? Append ' - Clone' to title - Ajouter ’ – Clone’ au titre + Ajouter « – Clone » au titre Replace username and password with references @@ -1398,7 +1443,20 @@ Do you want to overwrite the passkey in %1 - %2? Imported from CSV file: %1 - + Importé du fichier CSV : %1 + + + No Title Selected + Aucun titre séléctionné + + + No title column was selected, entries will be hard to tell apart. +Are you sure you want to import? + Les entrées seront difficiles à distinguer, car aucune titre de colonne n'a été sélectionné. Êtes-vous sûr de vouloir importer ? + + + Tags + Étiquettes @@ -1463,6 +1521,14 @@ La base de données de sauvegarde est située sur %2 Recycle Bin Corbeille + + Database file read error. + Erreur de lecture du fichier de base de données. + + + No file path was provided. + Aucun chemin d’accès de fichier n’a été fourni. + DatabaseOpenDialog @@ -1603,51 +1669,58 @@ Afin d’empêcher que cette erreur survienne, vous devez accéder à « Param Select Key File: - + Sélectionner le fichier clé : <p>In addition to a password, you can use a secret file to enhance the security of your database. This file can be generated in your database's security settings.</p><p>This is <strong>not</strong> your *.kdbx database file!</p> - - - - Click to add a key file. - - - - <a href="#" style="text-decoration: underline">I have a key file</a> - + <p>Vous pouvez utiliser un fichier secret en plus du mot de passe pour renforcer la sécurité de votre base de données. Ce fichier peut être généré à partir des paramètres de sécurité de votre base.</p><p>Il ne s'agit <strong>pas</strong> de votre fichier de base de données *.kdbx !</p> Use hardware key [Serial: %1] - + Utiliser une clé matérielle [N° de série : %1] Use hardware key - + Utiliser une clé logicielle Your database file is NOT a key file! If you don't have a key file or don't know what that is, you don't have to select one. - + Votre fichier de base de données n'est PAS un fichier clé ! +Si vous ne disposez pas de fichier clé ou ne savez pas de quoi il s'agit, n'en sélectionnez pas. KeePassXC database file selected - + Fichier de base de données KeePassXC sélectionné The file you selected looks like a database file. A database file is NOT a key file! Are you sure you want to continue with this file?. - + Le fichier sélectionné ne semble pas être une base de données. +Un fichier de base de données n'est pas un fichier clé ! +Voulez-vous poursuivre avec ce fichier ? No hardware keys found. - + Aucune clé matérielle trouvée. Refresh Hardware Keys - + Actualiser les clés logicielles + + + Click to add a key file. + Cliquer pour ajouter un fichier clé + + + <a href="#" style="text-decoration: underline">I have a key file</a> + <a href="#" style="text-decoration: underline">Je dispose d'un fichier clé</a> + + + Hardware keys found, but no slots are configured. + Clés matérielles trouvées, mais aucun emplacement n'est configuré. @@ -1683,6 +1756,22 @@ Are you sure you want to continue with this file?. Maintenance Maintenance + + KeeShare + KeeShare + + + Secret Service Integration + Intégration au Secret Service + + + Remote Sync + Synchronisation à distance + + + Database Settings: %1 + + DatabaseSettingsWidgetBrowser @@ -1852,14 +1941,14 @@ Voulez-vous vraiment poursuivre sans mot de passe ? Weak password Mot de passe faible - - You must enter a stronger password to protect your database. - Vous devez saisir un mot de passe plus fort pour protéger votre base de données. - This is a weak password! For better protection of your secrets, you should choose a stronger password. Le mot de passe est trop faible ! Pour une protection efficace, choisissez un mot de passe plus fort. + + The provided password does not meet the minimum quality requirement. + Le mot de passe fourni ne répond pas aux exigences minimales demandées. + DatabaseSettingsWidgetEncryption @@ -2161,6 +2250,50 @@ de la base de données. Autosave delay since last change checkbox Case à cocher de durée entre dernière modification et sauvegarde automatique + + Public Database Metadata + Métadonnées de la Base de données Publique + + + Warning: the following settings are not encrypted. + Avertissement : les paramètres suivants ne sont pas chiffrés. + + + Display name: + Nom d'affichage : + + + Publically visible display name used on the unlock dialog + Nom d'affichage publiquement visible utilisé sur la boîte de dialogue de déverrouillage + + + Database public display name + Nom d'affichage public de la base de données + + + Display color: + Couleur d'affichage: + + + Publically visible color used on the unlock dialog + Couleur publiquement visible utilisé sur la boîte de dialogue de déverrouillage + + + Database public display color chooser + Sélecteur de couleur d'affichage publique de la base de donnée + + + Clear + Effacer + + + Display icon: + Icône d'affichage : + + + Select Database Icon + Sélectionner l'Icône de Base de données + DatabaseSettingsWidgetKeeShare @@ -2256,6 +2389,141 @@ de la base de données. Champ de description de la base de données + + DatabaseSettingsWidgetRemote + + Sync Commands + Commandes de synchronisation. + + + Remove + Supprimer + + + Command Settings + Paramètres de la commande + + + Name + Nom + + + Save + Enregistrer + + + Download + Téléchargement + + + Command: + Commande: + + + Download command field + Champ de la commande de téléchargement + + + e.g.: "sftp user@hostname" or "scp user@hostname:DatabaseOnRemote.kdbx {TEMP_DATABASE}" + Par exemple : "sftp login@machine" ou "scp login@machine:BaseDeDonneesDistante.kdbx {TEMP_DATABASE}" + + + Input: + Entrée : + + + Download input field + Champ d'entrée de téléchargement + + + Upload + Téléverser + + + Upload command field + Champ de la commande de téléversement + + + e.g.: "sftp user@hostname" or "scp {TEMP_DATABASE} user@hostname:DatabaseOnRemote.kdbx" + Par exemple : "sftp login@machine" ou "scp {TEMP_DATABASE} login@machine:BaseDeDonneesDistante.kdbx" + + + Upload input field + Champ d'entrée de téléversement + + + Name cannot be empty. + Le nom ne peut pas être vide. + + + Test + Test + + + Download command cannot be empty. + La commande de téléchargement ne peut pas être vide. + + + Download failed with error: %1 + Le téléchargement a échoué avec l'erreur: %1 + + + Download finished, but file %1 could not be found. + Le téléchargement est fini, mais le fichier %1 n'a pas pu être trouvé. + + + Download successful. + Téléchargement réussi. + + + Save Remote Settings + Enregistrer les paramètres distant + + + You have unsaved changes. Do you want to save them? + Vous avez des modifications non sauvegardées. Voulez vous les enregistrer ? + + + e.g.: +get DatabaseOnRemote.kdbx {TEMP_DATABASE} +exit +--- +{TEMP_DATABASE} is used as placeholder to store the database in a temporary location +The command has to exit. In case of `sftp` as last command `exit` has to be sent + + Par exemple : +get BaseDeDonneesDistante.kdbx {TEMP_DATABASE} +exit +--- +{TEMP_DATABASE} est utilisé comme motif de remplacement pour stocker la base de données dans un emplacement temporaire +La commande doit terminer. Dans le cas de "sftp" la dernière commande envoyée doit être "exit" + + + + e.g.: +put {TEMP_DATABASE} DatabaseOnRemote.kdbx +exit +--- +{TEMP_DATABASE} is used as placeholder to store the database in a temporary location +The command has to exit. In case of `sftp` as last command `exit` has to be sent + + Par exemple : +put {TEMP_DATABASE} BaseDeDonneesDistante.kdbx +exit +--- +{TEMP_DATABASE} est utilisé comme motif de remplacement pour stocker la base de données dans un emplacement temporaire +La commande doit terminer. Dans le cas de "sftp" la dernière commande envoyée doit être "exit" + + + + Timeout: + + + + seconds + secondes + + DatabaseTabWidget @@ -2329,6 +2597,11 @@ C’est très certainement un bogue, veuillez le signaler aux développeurs.Database tab name modifier %1 [verrouillé] + + %1 [Temporary] + Database tab name modifier + %1 [Temporaire] + DatabaseWidget @@ -2452,26 +2725,6 @@ Enregistrer les changements ? File has changed Le fichier a été modifié - - The database file has changed. Do you want to load the changes? - Le fichier de la base de données a été modifié. Voulez-vous le recharger ? - - - Merge Request - Demande de fusion - - - The database file has changed and you have unsaved changes. -Do you want to merge your changes? - Le fichier de la base de données a été modifié et vos changements ne sont pas enregistrés. -Voulez-vous fusionner vos changements ? - - - Could not open the new database file while attempting to autoreload. -Error: %1 - Impossible d’ouvrir le nouveau fichier de base de données en tentant de la recharger automatiquement. -Erreur : % 1 - Disable safe saves? Désactiver les enregistrements sécurisés ? @@ -2523,6 +2776,86 @@ Désactiver les enregistrements sécurisés et réessayer ? Database tab name modifier %1 [nouvelle base de données] + + Remote Sync did not contain any download or upload commands. + Synchronisation à distance ne contient aucune commande de téléversement ou de téléchargement. + + + Remote sync '%1' completed successfully! + Synchronisation à distance « %1 » réussie ! + + + Remote sync '%1' failed: %2 + Synchronisation à distance « %1 » échouée : %2 + + + Error while saving database %1: %2 + Erreur pendant l'enregistrement de la base de données %1 : %2 + + + Downloading... + Téléchargement… + + + Uploading... + Téléversement... + + + Syncing... + Synchronisation... + + + Remove passkey from entry + Supprimer la clé d'accès de l'entrée + + + Do you want to remove the passkey from this entry? + Voulez-vous supprimer la clé d'accès de cette entrée ? + + + The database file "%1" was modified externally + Le fichier de base de données « %1 » a été modifié de manière externe + + + Do you want to load the changes? + Voulez-vous charger les changements ? + + + Reload database + Recharger la base de données + + + Reloading database… + Rechargement de la base de données… + + + Reload canceled + Rechargement annulé + + + Reload successful + Rechargement réussi + + + Reload pending user action… + Rechargement en attente d'une action de l'utilisateur… + + + The database file "%1" was modified externally.<br>How would you like to proceed?<br><br>Merge all changes<br>Ignore the changes on disk until save<br>Discard unsaved changes + Le fichier de base de données "%1" a été modifiée extérieurement.<br>Comment souhaitez-vous procéder ?<br><br>Fusionner tous les changements<br>Ignorer les changements sur le disque jusqu'à l'enregistrement<br>Annuler les modifications non sauvegardées + + + The database file "%1" was modified externally.<br>How would you like to proceed?<br><br>Merge all changes then save<br>Overwrite the changes on disk<br>Discard unsaved changes + Le fichier de base de données "%1" a été modifié extérieurement.<br>Comment souhaitez-vous procéder ?<br><br>Fusionner tous les changements puis enregistrer<br>Écraser les changements sur le disque<br>Annuler les changements non enregistrés + + + Database file overwritten. + Fichier de base de données écrasé. + + + Database file on disk cannot be unlocked with current credentials.<br>Enter new credentials and/or present hardware key to continue. + Le fichier de base de données sur le disque ne peut pas être déverrouillé avec les identifiants actuels.<br>Saisissez de nouveaux identifiants et/ou présentez la clé matérielle pour poursuivre. + EditEntryWidget @@ -2574,10 +2907,6 @@ Désactiver les enregistrements sécurisés et réessayer ? n/a s.o. - - (encrypted) - (chiffrée) - Select private key Sélectionner un fichier clé @@ -2680,6 +3009,10 @@ Voulez-vous la corriger ? %n year(s) %n an%n d’années%n ans + + Failed to decrypt SSH key, ensure password is correct. + Échec lors du décryptage de la clé SSH, assurez-vous de la validité du mot de passe. + EditEntryWidgetAdvanced @@ -2851,18 +3184,10 @@ Voulez-vous la corriger ? Skip Auto-Submit for this entry Ignorer l’envoi automatique pour cette entrée - - Only send this setting to the browser for HTTP Auth dialogs. If enabled, normal login forms will not show this entry for selection. - N’envoyer ce paramètre au navigateur que pour les boîtes de dialogue d’authentification HTTP. Si cette option est activée, cette entrée ne sera pas présentée par les formulaires d’authentification normaux comme possibilité de sélection. - Use this entry only with HTTP Basic Auth N’utiliser cette entrée qu’avec l’authentification HTTP Basic - - Do not send this setting to the browser for HTTP Auth dialogs. If enabled, HTTP Auth dialogs will not show this entry for selection. - Ne pas envoyer ce paramètre au navigateur pour les boîtes de dialogue d’authentification HTTP. Si cette option est activée, cette entrée ne sera pas présentée comme possibilité de sélection par les boîtes de dialogue d’authentification HTTP. - Do not use this entry with HTTP Basic Auth Ne pas utiliser cette entrée avec l’authentification HTTP Basic @@ -2881,11 +3206,19 @@ Voulez-vous la corriger ? These settings affect the entry's behaviour with the browser extension. - + Ces paramètres ont un impact sur le comportement des entrées avec l'extension du navigateur. Additional URLs - + Autres URL + + + Only send this entry to the browser for HTTP Auth dialogs. If enabled, normal login forms will not show this entry for selection. + Envoyez cette entrée au navigateur uniquement pour les boîtes de dialogue d'authentification HTTP. Si cette option est activée, les formulaires de connexion normaux n'afficheront pas cette entrée pour la sélection. + + + Do not send this entry to the browser for HTTP Auth dialogs. If enabled, HTTP Auth dialogs will not show this entry for selection. + N'envoyez pas cette entrée au navigateur pour les boîtes de dialogue d'authentification HTTP. Si cette option est activée, les boîtes de dialogue d'authentification HTTP n'afficheront pas cette entrée pour la sélection. @@ -3109,6 +3442,10 @@ Voulez-vous la corriger ? seconds secondes + + Clear agent + Vider l'agent + EditGroupWidget @@ -3549,6 +3886,24 @@ This may cause the affected plugins to malfunction. %1 - Clone %1 – Cloner + + Passkey + Clé d'accès + + + Invalid conversion type: %1 + Le type de conversion est invalide : %1 + + + Invalid conversion syntax: %1 + La syntaxe de conversion est invalide : %1 + + + Invalid regular expression syntax %1 +%2 + La syntaxe de l’expression rationnelle est invalide %1 +%2 + EntryAttachments @@ -3557,6 +3912,21 @@ This may cause the affected plugins to malfunction. Impossible d'ouvrir le fichier « %1 » + + EntryAttachmentsDialog + + Form + Formulaire + + + File name + Nom de fichier + + + File contents... + Contenu du fichier + + EntryAttachmentsModel @@ -3594,14 +3964,6 @@ This may cause the affected plugins to malfunction. Remove Supprimer - - Rename selected attachment - Renommer le fichier joint sélectionné - - - Rename - Renommer - Open selected attachment Ouvrir le fichier joint sélectionné @@ -3718,6 +4080,18 @@ Would you like to overwrite the existing attachment? Le fichier joint « %1 » existe déjà. Voulez-vous écraser le fichier joint existant ? + + New + Nouvelle + + + Preview + Aperçu + + + Failed to preview an attachment: Attachment not found + Échec de l'aperçu du fichier joint : fichier introuvable + EntryAttributesModel @@ -3916,6 +4290,10 @@ Voulez-vous écraser le fichier joint existant ? Background Color Couleur d’arrière-plan + + Group Path + Chemin du Groupe + EntryPreviewWidget @@ -4277,7 +4655,7 @@ Vous pouvez activer le service d’icônes de sites Web de DuckDuckGo dans la se ImportWizard Import Wizard - + Assistant d'importation @@ -4288,7 +4666,7 @@ Vous pouvez activer le service d’icônes de sites Web de DuckDuckGo dans la se Entry count: %1 - + Nombre d'entrées : %1 Group @@ -4308,6 +4686,14 @@ Vous pouvez activer le service d’icônes de sites Web de DuckDuckGo dans la se Url + URL + + + Could not load key file. + + + + Could not open remote database. Password or key file may be incorrect. @@ -4319,7 +4705,7 @@ Vous pouvez activer le service d’icônes de sites Web de DuckDuckGo dans la se Import File Selection - + Sélection du fichier à importer Password: @@ -4335,7 +4721,7 @@ Vous pouvez activer le service d’icônes de sites Web de DuckDuckGo dans la se Import Into: - + Importer vers : New Database @@ -4347,31 +4733,31 @@ Vous pouvez activer le service d’icônes de sites Web de DuckDuckGo dans la se Existing Database: - + Base de données existante : Import File: - + Fichier à importer : Comma Separated Values (.csv) - + Valeurs séparées par des virgules (.csv) 1Password Export (.1pux) - + Exportation 1Password (.1pux) 1Password Vault (.opvault) - + Coffre-fort 1Password (.opvault) Bitwarden (.json) - + Bitwarden (.json) KeePass 1 Database (.kdb) - + Base de données KeePass 1 (.kdb) Open OPVault @@ -4379,7 +4765,7 @@ Vous pouvez activer le service d’icônes de sites Web de DuckDuckGo dans la se Select import file - + Sélectionner le fichier à importer All files @@ -4395,24 +4781,62 @@ Vous pouvez activer le service d’icônes de sites Web de DuckDuckGo dans la se Comma Separated Values - + Valeurs séparées par une virgule 1Password Export - + Exportation 1Password Bitwarden JSON Export - + Export JSON pour Bitwarden 1Password Vault - + Coffre-fort 1Password KeePass1 Database + Base de données KeePass1 + + + Proton Pass (.json) + Proton Pass (.json) + + + Proton Pass JSON Export + Export JSON pour Proton Pass + + + Temporary Database + + Command: + Commande: + + + e.g.: "sftp user@hostname" or "scp user@hostname:DatabaseOnRemote.kdbx {TEMP_DATABASE}" + Par exemple : "sftp login@machine" ou "scp login@machine:BaseDeDonneesDistante.kdbx {TEMP_DATABASE}" + + + Input: + Entrée : + + + e.g.: +get DatabaseOnRemote.kdbx {TEMP_DATABASE} +exit +--- +{TEMP_DATABASE} is used as placeholder to store the database in a temporary location +The command has to exit. In case of `sftp` as last commend `exit` has to be sent + + + + + Remote Database (.kdbx) + Base de données distante (.kdbx) + KMessageWidget @@ -5498,7 +5922,7 @@ Voulez-vous vraiment poursuivre avec ce fichier ? Show Menubar - + Afficher la barre de menus Show Toolbar @@ -5553,12 +5977,6 @@ Cette version ne devrait pas être utilisée en production. Expect some bugs and minor issues, this version is meant for testing purposes. NOTE : vous utilisez une pré-version de KeePassXC. Mise à part certains bogues et dysfonctionnements mineurs, cette version est destinée à des fins de test. - - - WARNING: Your Qt version may cause KeePassXC to crash with an On-Screen Keyboard. -We recommend you use the AppImage available on our downloads page. - AVERTISSEMENT : votre version de Qt pourrait entraîner le plantage de KeePassXC avec un clavier virtuel. -Nous vous recommandons d’utiliser l’AppImage proposée sur notre page de téléchargement. No Tags @@ -5614,15 +6032,15 @@ Nous vous recommandons d’utiliser l’AppImage proposée sur notre page de té 1Password 1PUX... - + 1Password 1PUX... Import a 1Password 1PUX file - + Importer un fichier 1Password 1PUX Import… - + Importer… Passkeys… @@ -5632,29 +6050,33 @@ Nous vous recommandons d’utiliser l’AppImage proposée sur notre page de té Import Passkey Importer une clé d'accès + + Remote S&ync… + S&ynchronisation à distance... + Quit Application - + Quitter l'application Open About Dialog - + Ouvrir la fenêtre À propos. Open Database - + Ouvrir une base de données Create Database - + Créer une base de données Merge From Database - + Fusionner depuis la base de données Create Entry - + Créer une entrée Edit Entry @@ -5662,11 +6084,11 @@ Nous vous recommandons d’utiliser l’AppImage proposée sur notre page de té Delete Entry - + Supprimer l'entrée Create Group - + Créer un groupe Edit Group @@ -5674,51 +6096,51 @@ Nous vous recommandons d’utiliser l’AppImage proposée sur notre page de té Delete Group - + Supprimer le groupe Download All Favicons - + Télécharger tous les favicons. Sort Groups A-Z - + Trier les groupes de A-Z Sort Groups Z-A - + Trier les groupes de Z-A Save Database As - + Enregistrer la base de données sous... Show Database Security - + Afficher les informations de sécurité de la base de données Show Database Reports - + Afficher un rapport sur la base de données Show Database Settings - + Afficher les paramètres de la base de données Show Passkeys - + Afficher les clés d'accès Clone Entry - + Cloner l'entrée Move Entry Up - + Monter l'entrée Move Entry Down - + Descendre l'entrée Copy Username @@ -5730,51 +6152,55 @@ Nous vous recommandons d’utiliser l’AppImage proposée sur notre page de té Show Application Settings - + Afficher les paramètres de l'application Show Password Generator - + Afficher le générateur de mot de passe + + + Remove Passkey From Entry + Supprimer la clé d'accès de l'entrée Perform Auto-Type: {USERNAME} - + Remplir automatiquement : {LOGIN} Perform Auto-Type: {USERNAME}{ENTER} - + Remplir automatiquement : {LOGIN}{ENTRÉE} Perform Auto-Type: {PASSWORD} - + Remplir automatiquement : {MOTDEPASSE} Perform Auto-Type: {PASSWORD}{ENTER} - + Remplir automatiquement : {MOTDEPASSE}{ENTRÉE} Perform Auto-Type: {TOTP} - + Remplir automatiquement : {TOTP} Copy Title - + Copier le titre Copy URL - + Copier l'URL Copy Notes - + Copier les notes Export to CSV - + Exporter en CSV Export to HTML - + Exporter au format HTML Import KeePass1 Database @@ -5782,15 +6208,15 @@ Nous vous recommandons d’utiliser l’AppImage proposée sur notre page de té Import 1Password Vault - + Importer depuis un coffre-fort 1Password Import CSV File - + Importer un fichier CSV Show TOTP QR Code - + Afficher le QR Code TOTP Set up TOTP @@ -5798,87 +6224,115 @@ Nous vous recommandons d’utiliser l’AppImage proposée sur notre page de té Empty Recycle Bin - + Vider la corbeille Open Donation Website - + Faire un don Open Bug Report - + Ouvrir un rapport de bogue Open Online Documentation - + Ouvrir la documentation en ligne Open Keyboard Shortcuts Guide - + Ouvrir le guide des raccourcis clavier Save Database Backup - + Enregistrer une copie de sécurité de la base de données SSH Agent: Add Key - + SSH Agent : ajouter une clé SSH Agent: Remove Key - + SSH Agent : supprimer une clé Toggle Compact Mode - + Permuter le mode de compatibilité Set Theme: Automatic - + Définir le thème : automatique Set Theme: Light - + Définir le thème : clair Set Theme: Dark - + Définir le thème : foncé Set Theme: Classic - + Définir le thème : classique Toggle Show Menubar - + Permuter l'affichage de la barre de menus Toggle Show Toolbar - + Permuter l'affichage de la barre d'outils Toggle Show Preview Panel - + Permuter l'affichage du panneau d'aperçu Toggle Always on Top - + Permuter le mode Toujours devant Toggle Hide Usernames - + Permuter la masquage des noms d'utilisateur Toggle Hide Passwords - + Permuter la masquage des mots de passe Export to XML - + Exporter au format XML Toggle Allow Screen Capture - + Permuter l'autorisation de capture d'écran + + + Show Group Panel + Afficher le panneau de groupe + + + Toggle Show Group Panel + Permuter l'affichage du panneau d'aperçu + + + Setup Remote Sync… + Configurer la synchronisation à distance... + + + Password Generator + Générateur de mots de passe + + + E&xpire Entry… + Faire expirer l'entrée… + + + Clear SSH Agent + Vider l'agent SSH + + + Clear all identities in ssh-agent + Effacer toutes les identités dans ssh-agent @@ -6030,6 +6484,25 @@ Nous vous recommandons d’utiliser l’AppImage proposée sur notre page de té Veuillez saisir le nom d’affichage et une description facultative pour votre nouvelle base de données : + + NewEntryAttachmentsDialog + + Attachment name cannot be empty + Le nom du fichier joint ne peut pas être vide + + + Attachment with the same name already exists + Un fichier joint avec un nom identique existe déjà + + + Save attachment + Enregistrer le fichier attaché + + + New entry attachment + Nouveau fichier joint de l'entrée + + NixUtils @@ -6217,6 +6690,10 @@ Nous vous recommandons d’utiliser l’AppImage proposée sur notre page de té Unexpected EOF when writing private key Fin de fichier inattendue lors de l’écriture de la clé privée + + (encrypted) + (chiffrée) + OpenSSHKeyGenDialog @@ -6265,7 +6742,7 @@ Nous vous recommandons d’utiliser l’AppImage proposée sur notre page de té Export the following passkey entries. - + Exporter les entrées avec clé d'accès suivantes. @@ -6338,15 +6815,15 @@ Le remplacer ? Import the following passkey: - + Importer les clés d'accès suivantes : Import the following passkey to this entry: - + Exporter la clé d'accès de cette entrée : Default passkeys group (Imported Passkeys) - + Groupe par défaut des clés d'accès (clés importées) @@ -6369,25 +6846,27 @@ Le remplacer ? Open passkey file - + Ouvrir un fichier de clé d'accès Cannot import passkey - + Impossible d'importer la clé d'accès Cannot import passkey file "%1". Data is missing. - + Impossible d'importer le fichier de clé d'accès « %1 ». Données manquantes. Cannot import passkey file "%1". The following data is missing: %2 - + Impossible d'importer le fichier de clé d'accès « %1 ». +La donnée suivante est manquante : +%2 Cannot import passkey file "%1". Private key is missing or malformed. - + Impossible d'importer le fichier de clé d'accès « %1 ». La clé privée est manquante ou incorrecte. @@ -6568,10 +7047,6 @@ The following data is missing: Also choose from: Choisir aussi parmi : - - Excluded characters: "0", "1", "l", "I", "O", "|", "﹒" - Les caractères exclus sont : « 0 », « 1 », « l », « I », « O », « | », « . » - Exclude look-alike characters Exclure les caractères qui se ressemblent @@ -6596,10 +7071,6 @@ The following data is missing: Word Count: Nombre de mots : - - Character Count: - Nombres de caractères : - Word Case: Casse des mots : @@ -6612,10 +7083,6 @@ The following data is missing: Add custom wordlist Ajout d'une liste de mots personnalisée - - character - caractère - Close Fermer @@ -6722,6 +7189,22 @@ Voulez-vous la remplacer ? Special Characters Caractères spéciaux + + passwordLength + longueurMotdepasse + + + Characters: %1 + Caractères : %1 + + + MIXED case + Casse mixte + + + Excluded characters: "0", "1", "l", "I", "O", "|", "﹒", "B", "8", "G", "6" + Caractères exclus: "0", "1", "l", "I", "O", "|", "﹒", "B", "8", "G", "6" + PasswordWidget @@ -6789,6 +7272,21 @@ Voulez-vous la remplacer ? Appuyez sur &Tabulation entre les caractères + + PreviewEntryAttachmentsDialog + + Preview entry attachment + Aperçu du fichier joint de l'entrée + + + No preview available + Aucun aperçu disponible + + + Image format not supported + Format d’image non pris en charge + + QMessageBox @@ -7060,7 +7558,7 @@ Voulez-vous la remplacer ? No export target given. Please use '--stdout' or specify an 'export-file'. - Pas de cible d'export fourni. Merci d'utiliser '--stdout' ou spécifier un 'fichier d'export'. + Pas de cible d'export fourni. Merci d'utiliser « --stdout » ou spécifier un « fichier d'export ». Could not open output file %1. @@ -7467,10 +7965,6 @@ Voulez-vous la remplacer ? Invalid word count %1 Le nombre de mots %1 est invalide - - The word list is too small (< 1000 items) - La liste de mots est trop courte (moins de 1 000 articles) - Title for the entry. Titre de l’entrée. @@ -7615,10 +8109,6 @@ Voulez-vous la remplacer ? Exit interactive mode. Quitter le mode interactif. - - Format to use when exporting. Available choices are 'xml' or 'csv'. Defaults to 'xml'. - Format à utiliser lors de l’exportation. Les choix proposés sont « xml » ou « csv ». La valeur par défaut est « xml ». - Exports the content of a database to standard output in the specified format. Exporte au format indiqué le contenu de la base de données vers la sortie standard. @@ -8206,18 +8696,6 @@ Noyau : %3 %4 file empty fichier vide - - malformed string - chaîne mal formée - - - missing closing quote - Le guillemet fermant manque - - - %1: (row, col) %2,%3 - %1 : (ligne, colonne) %2, %3 - AES 256-bit AES 256 bits @@ -8461,11 +8939,12 @@ Noyau : %3 %4 Set the key file for the database. This option is deprecated, use --set-key-file instead. - + Définir le fichier clé pour la base. +Cette option est obsolète, utilisez plutôt --set-key-file. Databases have been locked. - + Les bases de données ont été verrouillées. Attestation not supported @@ -8553,122 +9032,198 @@ This option is deprecated, use --set-key-file instead. Origin is empty or not allowed - + La source est vide ou non autorisée Effective domain is not a valid domain - + Le véritable domaine est invalide Origin and RP ID do not match - + La source et l'identifiant du tiers ne correspondent pas No supported algorithms were provided - + Aucun algorithme pris en charge n'a été proposé Wait for timer to expire - + Veuillez attendre l'expiration du délai Challenge is shorter than required minimum length - + La longueur de l'interrogation subsidiaire est inférieure au minium requis user.id does not match the required length - + utilisateur.identifiant n'a pas la longueur requise Favorite Tag for favorite entries - + Favori File does not exist. - + Le fichier n'existe pas. Cannot open file: %1 - + Ouverture du fichier impossible : %1 Cannot parse file: %1 at position %2 - + Analyse impossible du fichier : %1 à la position %2 Failed to decrypt json file: %1 - + Échec lors du décryptage du fichier JSON : %1 Invalid encKeyValidation field - + Champ encKeyValidation invalide Invalid cipher list within encKeyValidation field - + Liste de chiffrement invalide dans le champ encKeyValidation Wrong password - + Mot de passe erroné Invalid encrypted data field - + Champ de données cryptées invalide Invalid cipher list within encrypted data field - + Liste de chiffrement invalide dans le champ des données chiffrées Cannot initialize cipher - + Impossible d'initialiser le chiffrement Cannot decrypt data - + Impossible de décrypter les données Bitwarden Import - + Importation Bitwarden Archived Tag for archived entries - + Archivé Invalid 1PUX file format: Not a valid ZIP file. - + Format de fichier 1PUX : fichier ZIP invalide. Invalid 1PUX file format: Missing export.data - + Format de fichier 1PUX : export.data manquant. 1Password Import - + Importation 1Password Enter Shortcut - + Saisir le raccourci Action - + Action Shortcuts - - - - Unsupported KDF type, cannot decrypt json file - + Raccourcis Unknown passkeys error + Erreur de clés d'accès inconnue + + + Invalid KDF iterations, cannot decrypt json file + Itérations KDF invalides, impossible de déchiffrer le fichier json. + + + Unsupported format, ensure your Bitwarden export is password-protected + Format non pris en charge, assurez-vous que l'export Bitwarden protège les mots de passe + + + Only PBKDF and Argon2 are supported, cannot decrypt json file + Seuls PBKDF et Argon2 sont pris en charge, impossible de déchiffrer le fichier json. + + + Reset Shortcuts + Réinitialiser les raccourcis + + + Double click an action to change its shortcut + Double-cliquez sur une action pour modifier son raccourci + + + Filter... + Filtrer... + + + Shortcut Conflict + Conflit de raccourcis + + + Shortcut %1 conflicts with '%2'. Overwrite shortcut? + Le raccourci %1 est en conflit avec « %2 » : faut-il écraser le raccourci ? + + + Cannot generate valid passphrases because the wordlist is too short + Impossible de générer des phrases de passe valides, car la liste de mots est trop courte. + + + Encrypted files are not supported. + Les fichiers chiffrés ne sont pas pris en charge. + + + Proton Pass Import + Import pour Proton Pass + + + Delete plugin data? + Supprimer les données de l’extension ? + + + Delete plugin data from Entry(s)? + Supprimer les données du greffon depuis l'entrée?Supprimer les données du greffon depuis les entrées?Supprimer les données du greffon depuis l(es) entrée(s)? + + + Passkey + Clé d'accès + + + Format to use when exporting. Available choices are 'xml', 'csv' or 'html'. Defaults to 'xml'. + Format à utiliser lors de l'exportation. Les choix proposés sont « xml », « csv » ou « html ». La valeur par défaut est « xml ». + + + start minimized to the system tray + Démarrer réduit à la zone de notification système + + + malformed string, possible unescaped delimiter + + missing closing delimiter + + + + %1, row: %2, column: %3 + + + + Tags + Étiquettes + QtIOCompressor @@ -8704,6 +9259,37 @@ This option is deprecated, use --set-key-file instead. Erreur interne zlib : + + RemoteHandler + + Command `%1` did not finish in time. Process was killed. + La commande « %1 » n'a pas terminé à temps. Le processus a été tué. + + + Failed to upload merged database. Command `%1` did not finish in time. Process was killed. + Échec du téléversement de la base de données fusionnée. La commande "%1" n'a pas terminé à temps. Le processus a été tué. + + + Invalid download parameters provided. + Les paramètres de téléchargement fournis sont incorrects. + + + Command `%1` failed to download database. + La commande « %1 » n’a pas pu télécharger la base de données. + + + Invalid database pointer or upload parameters provided. + L'adresse de base de données ou les paramètres de téléversement fournis sont incorrects. + + + Command `%1` exited with status code: %2 + La commande « %1 » s'est terminée avec le code d'état : %2 + + + Failed to upload merged database. Command `%1` exited with status code: %2 + Échec du téléversement de la base de données fusionnée. La commande "%1" s'est terminée avec le code d'état : %2 + + ReportsWidgetBrowserStatistics @@ -8770,6 +9356,10 @@ This option is deprecated, use --set-key-file instead. Exclude from reports Exclure des rapports + + Expire Entry(s)… + Entrée expiréeEntrées expiréesEntrée(s) expirée(s) + Only show entries that have a URL N’afficher que les entrées disposant d'une URL @@ -8786,36 +9376,33 @@ This option is deprecated, use --set-key-file instead. (Expired) (expirée) + + Delete plugin data from Entry(s)… + Supprimer les données du greffon depuis l'entrée…Supprimer les données du greffon depuis les entrées…Supprimer les données du greffon depuis l(es) entrée(s)… + ReportsWidgetHealthcheck - Hover over reason to show additional details. Double-click entries to edit. - Survolez la raison pour afficher des détails supplémentaires. Double-cliquez sur les entrées pour les modifier. + Show expired entries + Afficher les entrées expirées - Bad - Password quality - Mauvais + (Expired) + (expirée) + + + Hover over reason to show additional details. Double-click entries to edit. + Survolez la raison pour afficher des détails supplémentaires. Double-cliquez sur les entrées pour les modifier. Bad — password must be changed Mauvais – le mot de passe doit être changé - - Poor - Password quality - Plutôt mauvais - Poor — password should be changed Plutôt mauvais – le mot de passe doit être changé - - Weak - Password quality - Faible - Weak — consider changing the password Faible – envisagez de changer le mot de passe @@ -8864,18 +9451,14 @@ This option is deprecated, use --set-key-file instead. Exclude from reports Exclure des rapports - - Show expired entries - Afficher les entrées expirées + + Expire Entry(s)… + Entrée expiréeEntrées expiréesEntrée(s) expirée(s) Show entries that have been excluded from reports Afficher les entrées exclues des rapports - - (Expired) - (expirée) - ReportsWidgetHibp @@ -8971,6 +9554,10 @@ This option is deprecated, use --set-key-file instead. Exclude from reports Exclure des rapports + + Expire Entry(s)… + Entrée expiréeEntrées expiréesEntrée(s) expirée(s) + ReportsWidgetPasskeys @@ -9028,15 +9615,15 @@ This option is deprecated, use --set-key-file instead. The passkey file will be vulnerable to theft and unauthorized use, if left unsecured. Are you sure you want to continue? - + Le fichier de clé d'accès sera exposé au vol où à une utilisation non autorisée s'il n'est pas sécurisé. Êtes-vous sûr·e de vouloir continuer ? Please wait, list of entries with passkeys is being updated… - + Veuillez patienter pendant la mise à jour de la liste des entrées avec clé d'accès… No entries with passkeys. - + Aucun entrée avec clé d'accès. @@ -9212,6 +9799,14 @@ This option is deprecated, use --set-key-file instead. No agent running, cannot list identities. Aucun agent n’est en cours d’exécution, il est impossible de lister les identités. + + Failed to remove all SSH identities from agent. + Impossible de supprimer toutes les identités SSH de l’agent. + + + All SSH identities removed from agent. + Toutes les identités SSH sont supprimées de l'agent. + SearchHelpWidget @@ -9386,11 +9981,12 @@ This option is deprecated, use --set-key-file instead. <html><head/><body><p>This setting does not override disabling recycle bin prompts </p></body></html> - + <html><head/><body><p>Ce paramètre ne se substitue pas à la désactivation des confirmations de suppression vers la corbeille. </p></body></html> <html><head/><body><p>This improves compatibility with certain applications which search for password without unlocking the database first.</p><p>But enabling this may also crash the client if the database can not be unlocked within a certain timeout. (Usually 25s, but may be a different value set in applications.) </p></body></html> - + <html><head/><body><p>Permet d'améliorer la compatibilité avec certaines applications recherchant le mot de passe sans avoir à déverrouiller la base de données. +</p><p>L'activation de cette fonction peut toutefois faire planter la partie client si la base de données ne peut être déverrouillée en temps imparti (habituellement 25 secondes, mais peut varier selon les applications).</p></body></html> @@ -9497,29 +10093,6 @@ This option is deprecated, use --set-key-file instead. Exporter vers %1 - - ShortcutSettingsWidget - - Double click an action to change its shortcut - - - - Shortcut Conflict - - - - Filter... - - - - Shortcut %1 conflicts with '%2'. Overwrite shortcut? - - - - Reset Shortcuts - - - TagModel @@ -9729,15 +10302,15 @@ Exemple : JBSWY3DPEHPK3PXP Create Database - + Créer une base de données Open Database - + Ouvrir une base de données Import File - + Importer un fichier @@ -9809,12 +10382,16 @@ Exemple : JBSWY3DPEHPK3PXP Aucune clé matérielle n’a été détectée - <p>If you own a <a href="https://www.yubico.com/">YubiKey</a> or <a href="https://onlykey.io">OnlyKey</a>, you can use it for additional security.</p><p>The key requires one of its slots to be programmed as <a href="https://docs.yubico.com/yesdk/users-manual/application-otp/challenge-response.html">HMAC-SHA1 Challenge-Response</a>.</p> - + Refresh hardware keys + Actualiser les clés matérielles - Refresh hardware keys - + <p>If you own a <a href="https://www.yubico.com/">YubiKey</a> or <a href="https://onlykey.io">OnlyKey</a>, you can use it for additional security.</p><p>The key requires one of its slots to be programmed with <a href="https://keepassxc.org/docs/#faq-yubikey-howto">Challenge-Response</a>.</p> + <p>Si vous possédez une <a href="https://www.yubico.com/">YubiKey</a> ou <a href="https://onlykey.io">OnlyKey</a>, vous pouvez l'utiliser pour renforcer la sécurité.</p><p>La clé nécessite que l'un de ses emplacements soit programmé avec <a href="https://keepassxc.org/docs/#faq-yubikey-howto">défi'réponse</a>.</p> + + + Hardware keys found, but no slots are configured + Des clés matérielles ont été trouvées, mais aucun emplacement n'est configuré @@ -9842,7 +10419,7 @@ Exemple : JBSWY3DPEHPK3PXP (NFC) %1 [%2] - Slot %3, %4 YubiKey display fields - + (NFC) %1 [%2] - Emplacement %3, %4 Press @@ -9894,12 +10471,12 @@ Exemple : JBSWY3DPEHPK3PXP %1 [%2] - Slot %3 YubiKey NEO display fields - + %1 [%2] - Emplacement %3 %1 [%2] - Slot %3, %4 YubiKey display fields - + %1 [%2] - Emplacement %3, %4 \ No newline at end of file diff --git a/share/translations/keepassxc_fr_CA.ts b/share/translations/keepassxc_fr_CA.ts index 16230f32e..4529da1aa 100644 --- a/share/translations/keepassxc_fr_CA.ts +++ b/share/translations/keepassxc_fr_CA.ts @@ -217,18 +217,50 @@ You must restart the application to set the new language. Would you like to restart now? Pour appliquer la nouvelle langue, vous devez redémarrer l’application. Voulez-vous la démarrer maintenant? - - Reset Settings? - Réinitialiser les paramètres? - - - Are you sure you want to reset all general and security settings to default? - Voulez-vous vraiment réinitialiser tous les paramètres généraux et de sécurité à leur valeur par défaut? - Select backup storage directory Sélectionner le dossier de sauvegarde + + Confirm Reset + + + + Are you sure you want to reset all settings to default? + + + + Import KeePassXC Settings + + + + Failed to import settings from %1, not a valid settings file. + + + + Export KeePassXC Settings + + + + Small + + + + Normal + + + + Medium + + + + Large + + + + Custom + + ApplicationSettingsWidgetGeneral @@ -280,25 +312,6 @@ Include beta releases when checking for updates Inclure les versions bêta lors de la vérification de la présence de mises à jour - - On database unlock, show entries that - Lors du déverrouillage d’une base de données, montrer les entrées qui - - - have expired - On database unlock, show entries that... - ont expiré - - - days - On database unlock, show entries that will expire within %1 days - jours - - - will expire within - On database unlock, show entries that... - expirera dans - File Management Gestion des fichiers @@ -323,22 +336,10 @@ Backup database file before saving Sauvegarder le fichier de la base de données avant d’enregistrer - - Backup destination - Destination de sauvegarde - - - Specifies the database backup file location. Occurrences of "{DB_FILENAME}" are replaced with the filename of the saved database without extension. {TIME:<format>} is replaced with the backup time, see https://doc.qt.io/qt-5/qdatetime.html#toString. <format> defaults to format string "dd_MM_yyyy_hh-mm-ss". - Spécifie l’emplacement du fichier de sauvegarde de la base de données. Les occurrences de « {DB_FILENAME} » sont remplacées par le nom de fichier de la base de données sauvegardée sans extension. {TIME:<format>} est remplacé par l’heure de sauvegarde (voir https://doc.qt.io/qt-5/qdatetime.html#toString). Par défaut, <format>utilise le format « dd_MM_yyyy_hh-mm-ss ». - {DB_FILENAME}.old.kdbx {DB_FILENAME}.ancienne.kdbx - - Choose... - Choisir… - Use alternative saving method (may solve problems with Dropbox, Google Drive, GVFS, etc.) Utiliser une méthode alternative de sauvegarde (peut résoudre des problèmes avec Dropbox, Google Drive, GVFS, etc.). @@ -505,6 +506,71 @@ Remember last typed entry for: Mémoriser la dernière entrée saisie pendant : + + On database unlock, show entries that will expire within + + + + On database unlock, show entries that will expire within + + + + days + number of days warning for password expiration + jours + + + Destination format: + + + + <html><head/><body><p><span style=" font-weight:600;">{DB_FILENAME}</span> is replaced with the filename of the saved database without extension</p><p><span style=" font-weight:600;">{TIME:&lt;format&gt;}</span> is replaced with the specified time format (default: dd_MM_yyyy_hh-mm-ss)</p><p>See the User Guide for more details</p></body></html> + + + + Choose folder... + + + + Show confirmation before moving entries to recycle bin + + + + Copy data on double clicking field in entry view + + + + Show toolbar + + + + Show the menu bar by pressing the Alt key + + + + Show menubar + + + + Import settings… + + + + Export settings… + + + + Open browser on double clicking URL field in entry view + + + + Font size: + + + + Font size selection + + ApplicationSettingsWidgetSecurity @@ -570,18 +636,6 @@ Hide passwords in the entry preview panel Cacher les mots de passe dans le panneau de prévisualisation des entrées - - Hide entry notes by default - Par défaut, cacher les notes des entrées - - - Move entries to recycle bin without confirmation - Déplacer les entrées vers la corbeille sans confirmation - - - Enable double click to copy the username/password entry columns - Activer le double-clic pour copier le nom d'utilisateur/mot de passe des colonnes d'entrées - Privacy Confidentialité @@ -594,6 +648,18 @@ Hide TOTP in the entry preview panel + + Lock databases when switching user + + + + Lock Options + + + + Hide notes in the entry preview panel + + AutoType @@ -641,20 +707,6 @@ Entry does not have attribute for PICKCHARS: %1 L'entrée n'a pas d'attribut pour PICKCHARS : %1 - - Invalid conversion type: %1 - Type de conversion invalide : %1 - - - Invalid conversion syntax: %1 - Syntaxe de conversion invalide : %1 - - - Invalid regular expression syntax %1 -%2 - Syntaxe d'expression régulière invalide %1 -%2 - Invalid placeholder: %1 Espace réservé invalide : %1 @@ -1022,10 +1074,6 @@ Do you want to overwrite the passkey in %1 - %2? General Général - - Browsers installed as snaps are currently not supported. - Les navigateurs installés en tant que snap ne sont pas pris en charge actuellement. - Enable integration for these browsers: Activer l’intégration pour ces navigateurs : @@ -1197,18 +1245,6 @@ Do you want to overwrite the passkey in %1 - %2? Custom extension ID ID d’extension personnalisé - - Due to Snap sandboxing, you must run a script to enable browser integration.<br />You can obtain this script from %1 - En raison du bac à sable de Snap, vous devez exécuter un script afin d’activer l’intégration aux navigateurs.<br />Vous pouvez obtenir ce script sur %1 - - - KeePassXC-Browser is needed for the browser integration to work. <br />Download it for %1 and %2 and %3. %4 - KeePassXC-Browser est nécessaire pour que l’intégration aux navigateurs fonctionne. <br />Téléchargez-la pour %1, %2 et %3. %4 - - - Please see special instructions for browser extension use below - Veuillez consulter ci-dessous les instructions spéciales de l’extension pour navigateurs - Executable Files Fichiers exécutables @@ -1257,6 +1293,14 @@ Do you want to overwrite the passkey in %1 - %2? Allow using localhost with passkeys + + KeePassXC-Browser is needed for the browser integration to work. <br />Download it for %1 and %2 and %3. + + + + Browsers installed using Snap or Flatpak are not supported with exception to Firefox installed using Snap. + + CloneDialog @@ -1399,6 +1443,19 @@ Do you want to overwrite the passkey in %1 - %2? Imported from CSV file: %1 + + No Title Selected + + + + No title column was selected, entries will be hard to tell apart. +Are you sure you want to import? + + + + Tags + + CsvParserModel @@ -1462,6 +1519,14 @@ La base de données de sauvegarde est située sur %2 Recycle Bin Corbeille + + Database file read error. + + + + No file path was provided. + + DatabaseOpenDialog @@ -1604,14 +1669,6 @@ Afin d’empêcher que cette erreur survienne, vous devez accéder à « Param <p>In addition to a password, you can use a secret file to enhance the security of your database. This file can be generated in your database's security settings.</p><p>This is <strong>not</strong> your *.kdbx database file!</p> - - Click to add a key file. - - - - <a href="#" style="text-decoration: underline">I have a key file</a> - - Use hardware key [Serial: %1] @@ -1644,6 +1701,18 @@ Are you sure you want to continue with this file?. Refresh Hardware Keys + + Click to add a key file. + + + + <a href="#" style="text-decoration: underline">I have a key file</a> + + + + Hardware keys found, but no slots are configured. + + DatabaseSettingWidgetMetaData @@ -1678,6 +1747,22 @@ Are you sure you want to continue with this file?. Maintenance Maintenance + + KeeShare + KeeShare + + + Secret Service Integration + Intégration à « Secret Service » + + + Remote Sync + + + + Database Settings: %1 + + DatabaseSettingsWidgetBrowser @@ -1848,11 +1933,11 @@ Voulez-vous vraiment poursuivre sans mot de passe? Le mot de passe est faible - You must enter a stronger password to protect your database. + This is a weak password! For better protection of your secrets, you should choose a stronger password. - This is a weak password! For better protection of your secrets, you should choose a stronger password. + The provided password does not meet the minimum quality requirement. @@ -2143,6 +2228,50 @@ removed from the database. Autosave delay since last change checkbox + + Public Database Metadata + + + + Warning: the following settings are not encrypted. + + + + Display name: + + + + Publically visible display name used on the unlock dialog + + + + Database public display name + + + + Display color: + + + + Publically visible color used on the unlock dialog + + + + Database public display color chooser + + + + Clear + Effacer + + + Display icon: + + + + Select Database Icon + + DatabaseSettingsWidgetKeeShare @@ -2238,6 +2367,129 @@ removed from the database. Champ de description de la base de données + + DatabaseSettingsWidgetRemote + + Sync Commands + + + + Remove + Supprimer + + + Command Settings + + + + Name + Nom + + + Save + Enregistrer + + + Download + + + + Command: + + + + Download command field + + + + e.g.: "sftp user@hostname" or "scp user@hostname:DatabaseOnRemote.kdbx {TEMP_DATABASE}" + + + + Input: + + + + Download input field + + + + Upload + + + + Upload command field + + + + e.g.: "sftp user@hostname" or "scp {TEMP_DATABASE} user@hostname:DatabaseOnRemote.kdbx" + + + + Upload input field + + + + Name cannot be empty. + + + + Test + + + + Download command cannot be empty. + + + + Download failed with error: %1 + + + + Download finished, but file %1 could not be found. + + + + Download successful. + + + + Save Remote Settings + + + + You have unsaved changes. Do you want to save them? + + + + e.g.: +get DatabaseOnRemote.kdbx {TEMP_DATABASE} +exit +--- +{TEMP_DATABASE} is used as placeholder to store the database in a temporary location +The command has to exit. In case of `sftp` as last command `exit` has to be sent + + + + + e.g.: +put {TEMP_DATABASE} DatabaseOnRemote.kdbx +exit +--- +{TEMP_DATABASE} is used as placeholder to store the database in a temporary location +The command has to exit. In case of `sftp` as last command `exit` has to be sent + + + + + Timeout: + + + + seconds + secondes + + DatabaseTabWidget @@ -2311,6 +2563,11 @@ C’est très certainement un bogue, veuillez le signaler aux développeurs.Database tab name modifier %1 [verrouillé] + + %1 [Temporary] + Database tab name modifier + + DatabaseWidget @@ -2434,26 +2691,6 @@ Enregistrer les changements? File has changed Le fichier a été modifié - - The database file has changed. Do you want to load the changes? - Le fichier de la base de données a été modifié. Voulez-vous le recharger? - - - Merge Request - Demande de fusion - - - The database file has changed and you have unsaved changes. -Do you want to merge your changes? - Le fichier de la base de données a été modifié et vos changements ne sont pas enregistrés. -Voulez-vous fusionner vos changements? - - - Could not open the new database file while attempting to autoreload. -Error: %1 - Impossible d’ouvrir le nouveau fichier de base de données en tentant de la recharger automatiquement. -Erreur : % 1 - Disable safe saves? Désactiver les enregistrements sécurisés? @@ -2505,6 +2742,86 @@ Désactiver les enregistrements sécurisés et réessayer? Database tab name modifier %1 [nouvelle base de données] + + Remote Sync did not contain any download or upload commands. + + + + Remote sync '%1' completed successfully! + + + + Remote sync '%1' failed: %2 + + + + Error while saving database %1: %2 + + + + Downloading... + Téléchargement… + + + Uploading... + + + + Syncing... + + + + Remove passkey from entry + + + + Do you want to remove the passkey from this entry? + + + + The database file "%1" was modified externally + + + + Do you want to load the changes? + + + + Reload database + + + + Reloading database… + + + + Reload canceled + + + + Reload successful + + + + Reload pending user action… + + + + The database file "%1" was modified externally.<br>How would you like to proceed?<br><br>Merge all changes<br>Ignore the changes on disk until save<br>Discard unsaved changes + + + + The database file "%1" was modified externally.<br>How would you like to proceed?<br><br>Merge all changes then save<br>Overwrite the changes on disk<br>Discard unsaved changes + + + + Database file overwritten. + + + + Database file on disk cannot be unlocked with current credentials.<br>Enter new credentials and/or present hardware key to continue. + + EditEntryWidget @@ -2556,10 +2873,6 @@ Désactiver les enregistrements sécurisés et réessayer? n/a s.o. - - (encrypted) - (chiffrée) - Select private key Sélectionner un fichier clé @@ -2658,6 +2971,10 @@ Would you like to correct it? %n year(s) % an%n an(s)%n an(s) + + Failed to decrypt SSH key, ensure password is correct. + + EditEntryWidgetAdvanced @@ -2829,18 +3146,10 @@ Would you like to correct it? Skip Auto-Submit for this entry Ignorer l’envoi automatique pour cette entrée - - Only send this setting to the browser for HTTP Auth dialogs. If enabled, normal login forms will not show this entry for selection. - N’envoyer ce paramètre au navigateur que pour les boîtes de dialogue d’authentification HTTP. Si cette option est activée, cette entrée ne sera pas présentée par les formulaires d’authentification normaux comme possibilité de sélection. - Use this entry only with HTTP Basic Auth N’utiliser cette entrée qu’avec l’authentification HTTP Basic - - Do not send this setting to the browser for HTTP Auth dialogs. If enabled, HTTP Auth dialogs will not show this entry for selection. - Ne pas envoyer ce paramètre au navigateur pour les boîtes de dialogue d’authentification HTTP. Si cette option est activée, cette entrée ne sera pas présentée comme possibilité de sélection par les boîtes de dialogue d’authentification HTTP. - Do not use this entry with HTTP Basic Auth Ne pas utiliser cette entrée avec l’authentification HTTP Basic @@ -2865,6 +3174,14 @@ Would you like to correct it? Additional URLs + + Only send this entry to the browser for HTTP Auth dialogs. If enabled, normal login forms will not show this entry for selection. + + + + Do not send this entry to the browser for HTTP Auth dialogs. If enabled, HTTP Auth dialogs will not show this entry for selection. + + EditEntryWidgetHistory @@ -3087,6 +3404,10 @@ Would you like to correct it? seconds secondes + + Clear agent + + EditGroupWidget @@ -3527,6 +3848,24 @@ This may cause the affected plugins to malfunction. %1 - Clone %1 – Cloner + + Passkey + + + + Invalid conversion type: %1 + Type de conversion invalide : %1 + + + Invalid conversion syntax: %1 + Syntaxe de conversion invalide : %1 + + + Invalid regular expression syntax %1 +%2 + Syntaxe d'expression régulière invalide %1 +%2 + EntryAttachments @@ -3535,6 +3874,21 @@ This may cause the affected plugins to malfunction. Impossible d’ouvrir le fichier "%1" + + EntryAttachmentsDialog + + Form + Formulaire + + + File name + + + + File contents... + + + EntryAttachmentsModel @@ -3572,14 +3926,6 @@ This may cause the affected plugins to malfunction. Remove Supprimer - - Rename selected attachment - - - - Rename - Renommer - Open selected attachment Ouvrir le fichier joint sélectionné @@ -3693,6 +4039,18 @@ Error: %1 Would you like to overwrite the existing attachment? + + New + + + + Preview + Aperçu + + + Failed to preview an attachment: Attachment not found + + EntryAttributesModel @@ -3891,6 +4249,10 @@ Would you like to overwrite the existing attachment? Background Color + + Group Path + + EntryPreviewWidget @@ -4284,6 +4646,14 @@ Vous pouvez activer le service d’icônes de sites Web de DuckDuckGo dans la se Url + + Could not load key file. + + + + Could not open remote database. Password or key file may be incorrect. + + ImportWizardPageSelect @@ -4387,6 +4757,44 @@ Vous pouvez activer le service d’icônes de sites Web de DuckDuckGo dans la se KeePass1 Database + + Proton Pass (.json) + + + + Proton Pass JSON Export + + + + Temporary Database + + + + Command: + + + + e.g.: "sftp user@hostname" or "scp user@hostname:DatabaseOnRemote.kdbx {TEMP_DATABASE}" + + + + Input: + + + + e.g.: +get DatabaseOnRemote.kdbx {TEMP_DATABASE} +exit +--- +{TEMP_DATABASE} is used as placeholder to store the database in a temporary location +The command has to exit. In case of `sftp` as last commend `exit` has to be sent + + + + + Remote Database (.kdbx) + + KMessageWidget @@ -5522,11 +5930,6 @@ This version is not meant for production use. Expect some bugs and minor issues, this version is meant for testing purposes. - - WARNING: Your Qt version may cause KeePassXC to crash with an On-Screen Keyboard. -We recommend you use the AppImage available on our downloads page. - - No Tags @@ -5599,6 +6002,10 @@ We recommend you use the AppImage available on our downloads page. Import Passkey + + Remote S&ync… + + Quit Application @@ -5703,6 +6110,10 @@ We recommend you use the AppImage available on our downloads page. Show Password Generator + + Remove Passkey From Entry + + Perform Auto-Type: {USERNAME} @@ -5847,6 +6258,34 @@ We recommend you use the AppImage available on our downloads page. Toggle Allow Screen Capture + + Show Group Panel + + + + Toggle Show Group Panel + + + + Setup Remote Sync… + + + + Password Generator + + + + E&xpire Entry… + + + + Clear SSH Agent + + + + Clear all identities in ssh-agent + + ManageDatabase @@ -5997,6 +6436,25 @@ We recommend you use the AppImage available on our downloads page. Veuillez saisir le nom d’affichage et une description facultative pour votre nouvelle base de données : + + NewEntryAttachmentsDialog + + Attachment name cannot be empty + + + + Attachment with the same name already exists + + + + Save attachment + + + + New entry attachment + + + NixUtils @@ -6184,6 +6642,10 @@ We recommend you use the AppImage available on our downloads page. Unexpected EOF when writing private key Fin de fichier inattendue lors de l’écriture de la clé privée + + (encrypted) + (chiffrée) + OpenSSHKeyGenDialog @@ -6534,10 +6996,6 @@ The following data is missing: Also choose from: Choisir aussi parmi : - - Excluded characters: "0", "1", "l", "I", "O", "|", "﹒" - - Exclude look-alike characters Exclure les caractères qui se ressemblent @@ -6562,10 +7020,6 @@ The following data is missing: Word Count: Nombre de mots : - - Character Count: - Nombre de caractères: - Word Case: Casse des mots : @@ -6578,10 +7032,6 @@ The following data is missing: Add custom wordlist Ajouter une liste de mots personnalisés - - character - - Close Fermer @@ -6687,6 +7137,22 @@ Do you want to overwrite it? Special Characters Caractères spéciaux + + passwordLength + + + + Characters: %1 + + + + MIXED case + + + + Excluded characters: "0", "1", "l", "I", "O", "|", "﹒", "B", "8", "G", "6" + + PasswordWidget @@ -6754,6 +7220,21 @@ Do you want to overwrite it? + + PreviewEntryAttachmentsDialog + + Preview entry attachment + + + + No preview available + + + + Image format not supported + + + QMessageBox @@ -7432,10 +7913,6 @@ Do you want to overwrite it? Invalid word count %1 Le nombre de mots %1 est invalide - - The word list is too small (< 1000 items) - La liste de mots est trop courte (moins de 1 000 articles) - Title for the entry. Titre de l’entrée. @@ -7580,10 +8057,6 @@ Do you want to overwrite it? Exit interactive mode. Quitter le mode interactif. - - Format to use when exporting. Available choices are 'xml' or 'csv'. Defaults to 'xml'. - Format à utiliser lors de l’exportation. Les choix proposés sont « xml » ou « csv ». La valeur par défaut est « xml ». - Exports the content of a database to standard output in the specified format. Exporte au format indiqué le contenu de la base de données vers la sortie standard. @@ -8171,18 +8644,6 @@ Noyau : %3 %4 file empty fichier vide - - malformed string - chaîne mal formée - - - missing closing quote - Le guillemet fermant manque - - - %1: (row, col) %2,%3 - %1 : (ligne, colonne) %2, %3 - AES 256-bit AES 256 bits @@ -8627,11 +9088,87 @@ This option is deprecated, use --set-key-file instead. - Unsupported KDF type, cannot decrypt json file + Unknown passkeys error - Unknown passkeys error + Invalid KDF iterations, cannot decrypt json file + + + + Unsupported format, ensure your Bitwarden export is password-protected + + + + Only PBKDF and Argon2 are supported, cannot decrypt json file + + + + Reset Shortcuts + + + + Double click an action to change its shortcut + + + + Filter... + + + + Shortcut Conflict + + + + Shortcut %1 conflicts with '%2'. Overwrite shortcut? + + + + Cannot generate valid passphrases because the wordlist is too short + + + + Encrypted files are not supported. + + + + Proton Pass Import + + + + Delete plugin data? + Supprimer les données de l’extension? + + + Delete plugin data from Entry(s)? + + + + Passkey + + + + Format to use when exporting. Available choices are 'xml', 'csv' or 'html'. Defaults to 'xml'. + + + + start minimized to the system tray + + + + malformed string, possible unescaped delimiter + + + + missing closing delimiter + + + + %1, row: %2, column: %3 + + + + Tags @@ -8669,6 +9206,37 @@ This option is deprecated, use --set-key-file instead. Erreur interne zlib : + + RemoteHandler + + Command `%1` did not finish in time. Process was killed. + + + + Failed to upload merged database. Command `%1` did not finish in time. Process was killed. + + + + Invalid download parameters provided. + + + + Command `%1` failed to download database. + + + + Invalid database pointer or upload parameters provided. + + + + Command `%1` exited with status code: %2 + + + + Failed to upload merged database. Command `%1` exited with status code: %2 + + + ReportsWidgetBrowserStatistics @@ -8735,6 +9303,10 @@ This option is deprecated, use --set-key-file instead. Exclude from reports Exclure des rapports + + Expire Entry(s)… + + Only show entries that have a URL @@ -8751,36 +9323,33 @@ This option is deprecated, use --set-key-file instead. (Expired) + + Delete plugin data from Entry(s)… + + ReportsWidgetHealthcheck - Hover over reason to show additional details. Double-click entries to edit. - Survolez la raison pour afficher des détails supplémentaires. Double-cliquez sur les entrées pour les modifier. + Show expired entries + - Bad - Password quality - Mauvais + (Expired) + + + + Hover over reason to show additional details. Double-click entries to edit. + Survolez la raison pour afficher des détails supplémentaires. Double-cliquez sur les entrées pour les modifier. Bad — password must be changed Mauvais - le mot de passe doit être changé - - Poor - Password quality - Plutôt mauvais - Poor — password should be changed Plutôt mauvais - le mot de passe doit être changé - - Weak - Password quality - Faible - Weak — consider changing the password Faible - envisagez de changer le mot de passe @@ -8829,18 +9398,14 @@ This option is deprecated, use --set-key-file instead. Exclude from reports Exclure des rapports - - Show expired entries - + + Expire Entry(s)… + Show entries that have been excluded from reports - - (Expired) - - ReportsWidgetHibp @@ -8936,6 +9501,10 @@ This option is deprecated, use --set-key-file instead. Exclude from reports Exclure des rapports + + Expire Entry(s)… + + ReportsWidgetPasskeys @@ -9177,6 +9746,14 @@ This option is deprecated, use --set-key-file instead. No agent running, cannot list identities. Aucun agent n’est en cours d’exécution, il est impossible de lister les identités. + + Failed to remove all SSH identities from agent. + + + + All SSH identities removed from agent. + + SearchHelpWidget @@ -9462,29 +10039,6 @@ This option is deprecated, use --set-key-file instead. Exporter vers %1 - - ShortcutSettingsWidget - - Double click an action to change its shortcut - - - - Shortcut Conflict - - - - Filter... - - - - Shortcut %1 conflicts with '%2'. Overwrite shortcut? - - - - Reset Shortcuts - - - TagModel @@ -9774,11 +10328,15 @@ Exemple : JBSWY3DPEHPK3PXP Aucune clé matérielle n’a été détectée - <p>If you own a <a href="https://www.yubico.com/">YubiKey</a> or <a href="https://onlykey.io">OnlyKey</a>, you can use it for additional security.</p><p>The key requires one of its slots to be programmed as <a href="https://docs.yubico.com/yesdk/users-manual/application-otp/challenge-response.html">HMAC-SHA1 Challenge-Response</a>.</p> + Refresh hardware keys - Refresh hardware keys + <p>If you own a <a href="https://www.yubico.com/">YubiKey</a> or <a href="https://onlykey.io">OnlyKey</a>, you can use it for additional security.</p><p>The key requires one of its slots to be programmed with <a href="https://keepassxc.org/docs/#faq-yubikey-howto">Challenge-Response</a>.</p> + + + + Hardware keys found, but no slots are configured diff --git a/share/translations/keepassxc_he.ts b/share/translations/keepassxc_he.ts index 138a7520b..7be663b90 100644 --- a/share/translations/keepassxc_he.ts +++ b/share/translations/keepassxc_he.ts @@ -86,7 +86,7 @@ Remember - זכירה + לזכור Allow Selected @@ -116,7 +116,7 @@ Use Pageant - שימוש בפג'יאנט + שימוש בפיג'אנט Use OpenSSH @@ -217,18 +217,50 @@ You must restart the application to set the new language. Would you like to restart now? נא לאתחל את היישום כדי להגדיר את השפה החדשה. האם לאתחל כעת? - - Reset Settings? - אפוס הגדרות? - - - Are you sure you want to reset all general and security settings to default? - האם לאפס את כל הגדרות הכלליות והאבטחה לברירת המחדל? - Select backup storage directory בחירת מחיצת אחסן גיבוי + + Confirm Reset + אישור שיצוב + + + Are you sure you want to reset all settings to default? + האם לשצב את כל ההגדרות לבררת מחדל? + + + Import KeePassXC Settings + ייבוא הגדרות KeePassXC + + + Failed to import settings from %1, not a valid settings file. + ייבוא הגדרות מ־%1 כשל, לא קובץ הגדרות תקין. + + + Export KeePassXC Settings + ייצוא הגדרות KeePassXC + + + Small + + + + Normal + + + + Medium + + + + Large + + + + Custom + + ApplicationSettingsWidgetGeneral @@ -238,11 +270,11 @@ Startup - איתחול + אתחול Start only a single instance of KeePassXC - איתחול אֶדְגָּם KeePassXC יחיד בלבד + אתחול אדגם KeePassXC יחיד בלבד Automatically launch KeePassXC at system startup @@ -280,25 +312,6 @@ Include beta releases when checking for updates הכללת גרסאות בטא בבדיקת עדכונים - - On database unlock, show entries that - עם נעילת מסד־נתונים, הצגת ערכים ש־ - - - have expired - On database unlock, show entries that... - פג־תוקף - - - days - On database unlock, show entries that will expire within %1 days - ימים - - - will expire within - On database unlock, show entries that... - תפוגת תוקף בתוך - File Management ניהול קבצים @@ -323,22 +336,10 @@ Backup database file before saving גיבוי קובץ מסד־נתונים לפני שמירה - - Backup destination - יעד גיבוי - - - Specifies the database backup file location. Occurrences of "{DB_FILENAME}" are replaced with the filename of the saved database without extension. {TIME:<format>} is replaced with the backup time, see https://doc.qt.io/qt-5/qdatetime.html#toString. <format> defaults to format string "dd_MM_yyyy_hh-mm-ss". - ציון מיקום קובץ גיבוי מסד־נתונים. מופעים של "{DB_FILENAME}" יוחלפו בשם קובץ מסד־נתונים השמור, ללא הסיומת. {TIME:<format>} יוחלף במועד הגיבוי, למידע נוסף https://doc.qt.io/qt-5/qdatetime.html#toString. ברירת המחדל של <format> היא תבנית המחרוזת "dd_MM_yyyy_hh-mm-ss". - {DB_FILENAME}.old.kdbx {DB_FILENAME}.old.kdbx - - Choose... - בחירה... - Use alternative saving method (may solve problems with Dropbox, Google Drive, GVFS, etc.) שימוש בשיטת שמירה חלופית (עשוי לפתור בעיות עם דרופבוקס, גוגל דרייב, GVFS ודומיהם). @@ -505,6 +506,71 @@ Remember last typed entry for: זכירת רשומה אחרונה שהוקלדה ל: + + On database unlock, show entries that will expire within + עם שחרור נעילת מסד־נתונים, להציג ערכים שתוקפם יפוג בתוך + + + On database unlock, show entries that will expire within + עם שחרור נעילת מסד־נתונים, להציג ערכים שתוקפם יפוג בתוך + + + days + number of days warning for password expiration + ימים + + + Destination format: + תסדיר יעד: + + + <html><head/><body><p><span style=" font-weight:600;">{DB_FILENAME}</span> is replaced with the filename of the saved database without extension</p><p><span style=" font-weight:600;">{TIME:&lt;format&gt;}</span> is replaced with the specified time format (default: dd_MM_yyyy_hh-mm-ss)</p><p>See the User Guide for more details</p></body></html> + + + + Choose folder... + בחירת תיקייה... + + + Show confirmation before moving entries to recycle bin + בקש אישור לפני העברת ערכים לסל המחזור + + + Copy data on double clicking field in entry view + + + + Show toolbar + הצגת סרגל־כלים + + + Show the menu bar by pressing the Alt key + + + + Show menubar + הצגת סרגל תפריט + + + Import settings… + ייבוא הגדרות... + + + Export settings… + ייצוא הגדרות... + + + Open browser on double clicking URL field in entry view + + + + Font size: + + + + Font size selection + + ApplicationSettingsWidgetSecurity @@ -570,18 +636,6 @@ Hide passwords in the entry preview panel הסתרת ססמאות בלוחית תצוגת רשומות מקדימה - - Hide entry notes by default - הסתרת הערות רשומה כברירת מחדל - - - Move entries to recycle bin without confirmation - העברת רשומות לסל המחזור ללא אישור - - - Enable double click to copy the username/password entry columns - איפשור הקשה כפולה להעתקת עמודות רשומה שם המשתמש/הססמה - Privacy פרטיות @@ -594,6 +648,18 @@ Hide TOTP in the entry preview panel הסתרת TOTP בלוחית תצוגת רשומות מקדימה + + Lock databases when switching user + נעילת מסדי־נתונים בהחלפת משתמש + + + Lock Options + אפשרויות נעילה + + + Hide notes in the entry preview panel + + AutoType @@ -641,20 +707,6 @@ Entry does not have attribute for PICKCHARS: %1 לרשומה אין תכונה עבור PICKCHARS: %1 - - Invalid conversion type: %1 - סוג המרה לא תקין: %1 - - - Invalid conversion syntax: %1 - תחביר המרה לא תקין: %1 - - - Invalid regular expression syntax %1 -%2 - תחביר ביטוי רגיל לא תקין %1 -%2 - Invalid placeholder: %1 מציין מיקום לא תקין: %1 @@ -714,7 +766,7 @@ Trying to send invalid keyboard symbol. - + ניסיון לשלוח סמל מקלדת לא תקין. @@ -870,11 +922,11 @@ Please select the correct database for saving credentials. Timeout in <b>%n</b> seconds... - + פסק זמן בתוך שניה <b>%n</b>...פסק זמן בתוך <b>%n</b> שניות...פסק זמן בתוך <b>%n</b> שניות... Relying Party: %1 - + צד סומך: %1 Username: %1 @@ -882,28 +934,29 @@ Please select the correct database for saving credentials. KeePassXC - Passkey credentials - + נתוני אמנה Passkey - KeePassXC Add to existing entry - + הוספה לרשומה קיימת Existing passkey found. Do you want to register a new passkey for: - + נמצאו Passkey קיימים. +האם לרשום Passkey חדש עבור: Select the existing passkey and press Update to replace it. - + בחירת ה־Passkey הקיים ולחיצה על עדכון כדי להחליפו. Authenticate passkey credentials for: - + אימות נתוני אמנת Passkey עבור: Do you want to register a passkey for: - + האם לרשום Passkey עבור: @@ -951,7 +1004,7 @@ Do you want to delete the entry? %1 (Passkey) - + %1 (Passkey) KeePassXC - Create a new group @@ -983,20 +1036,21 @@ Do you want to delete the entry? KeePassXC - Passkey credentials - + נתוני אמנה Passkey - KeePassXC Register a new passkey to this entry: - + רישום Passkey חדש לרשומה זו: KeePassXC - Update passkey - + KeePassXC – עדכון Passkey Entry already has a passkey. Do you want to overwrite the passkey in %1 - %2? - + קיים כבר Passkey לרשומה. +האם לכתוב על ה־Passkey ב־%1 - %2? Register @@ -1021,10 +1075,6 @@ Do you want to overwrite the passkey in %1 - %2? General כללי - - Browsers installed as snaps are currently not supported. - דפדפנים המותקנים כ־snaps לא נתמכים כעת. - Enable integration for these browsers: איפשור שילוב עם דפדפנים אלה: @@ -1196,18 +1246,6 @@ Do you want to overwrite the passkey in %1 - %2? Custom extension ID מזהה הרחבה מותאם אישית - - Due to Snap sandboxing, you must run a script to enable browser integration.<br />You can obtain this script from %1 - עקב ארגז־חול Snap, יש להריץ תסריט בכדי לאפשר שילוב דפדפן. <br /> ניתן להפיק את התסריט מ־%1 - - - KeePassXC-Browser is needed for the browser integration to work. <br />Download it for %1 and %2 and %3. %4 - על מנת ששילוב הדפדפן יעבוד, נדרשKeePassXC־Browser <br /> ניתן להורד אותו ל־%1 ו־%2 ו־%3. %4 - - - Please see special instructions for browser extension use below - נא לעיין בהוראות מיוחדות לשימוש בהרחבת הדפדפן להלן - Executable Files קבצי הפעלה @@ -1234,7 +1272,7 @@ Do you want to overwrite the passkey in %1 - %2? <b>Warning:</b> Only adjust these settings if necessary. - + <b>אזהרה:</b> לכוונן הגדרות אלו בלבד ככוש שנדרש. The custom proxy location does not exist. @@ -1242,18 +1280,26 @@ Do you want to overwrite the passkey in %1 - %2? <b>Error:</b> The custom proxy location does not exist. Correct this in the advanced settings tab. - + <b>שגיאה:</b> מיקום המתווך המותאם אישית לא קיים. נא לתקן זאת בלשונית הגדרות מתקדמות. <b>Error:</b> The installed proxy executable is missing from the expected location: %1<br/>Please set a custom proxy location in the advanced settings or reinstall the application. - + <b>שגיאה:</b> המתווך הבציע המותקן חסר במיקום הצפוי: %1<br/> נא לקבוע מיקום מתווך מותאם אישית בהגדרות מתקדמות או להתקין מחדש את היישום. Allows using insecure http://localhost with passkeys for testing purposes. - + אפשור שימוש ב־http://localhost לא מאובטח למטרות בדיקה. Allow using localhost with passkeys + אפשור שימוש ב־localhost עם passkeys + + + KeePassXC-Browser is needed for the browser integration to work. <br />Download it for %1 and %2 and %3. + דפדפן – KeePassXC נדרש כדי שתכלול דפדפן יפעל. <br /> ניתן להורידו עבור %1 ו־%2 ו־%3. + + + Browsers installed using Snap or Flatpak are not supported with exception to Firefox installed using Snap. @@ -1396,7 +1442,21 @@ Do you want to overwrite the passkey in %1 - %2? Imported from CSV file: %1 - + יובא מקובץ CSV: %1 + + + No Title Selected + לא נבחרה כותרת + + + No title column was selected, entries will be hard to tell apart. +Are you sure you want to import? + לא נבחרה כותרת עמודה, יהיה קשה להבחין בין רשומות. +האם לייבא? + + + Tags + תגים @@ -1461,6 +1521,14 @@ Backup database located at %2 Recycle Bin סל־מחזור + + Database file read error. + + + + No file path was provided. + + DatabaseOpenDialog @@ -1567,11 +1635,11 @@ To prevent this error from appearing, you must go to "Database Settings / S Old key file format - תבנית קובץ מפתח ישן + תסדיר קובץ מפתח ישן You are using an old key file format which KeePassXC may<br>stop supporting in the future.<br><br>Please consider generating a new key file by going to:<br><strong>Database &gt; Database Security &gt; Change Key File.</strong><br> - נעשה שימוש בתבנית קובץ מפתח ישן ש־KeePassXC עשוי<br>להפסיק לתמוך בעתיד.<br><br>נא שקול ליצור קובץ מפתח חדש מהתפריט:<br><strong>מסד־נתונים -> אבטחת מסד־נתונים -> שינוי קובץ מפתח.</strong><br> + נעשה שימוש בתסדיר קובץ מפתח ישן ש־KeePassXC עשוי<br>להפסיק לתמוך בעתיד.<br><br>נא שקול ליצור קובץ מפתח חדש מהתפריט:<br><strong>מסד־נתונים -> אבטחת מסד־נתונים -> שינוי קובץ מפתח.</strong><br> Don't show this warning again @@ -1599,7 +1667,7 @@ To prevent this error from appearing, you must go to "Database Settings / S Failed to authenticate with Quick Unlock: %1 - + אימות עם שחרור נעילה מהיר כשל: %1 Select Key File: @@ -1607,15 +1675,7 @@ To prevent this error from appearing, you must go to "Database Settings / S <p>In addition to a password, you can use a secret file to enhance the security of your database. This file can be generated in your database's security settings.</p><p>This is <strong>not</strong> your *.kdbx database file!</p> - - - - Click to add a key file. - הקשה להוספת קובץ מפתח חדש. - - - <a href="#" style="text-decoration: underline">I have a key file</a> - <a href="#" style="text-decoration: underline">יש ברשותי קובץ מפתח</a> + <p> בנוסף לססמה, ניתן להשתמש בקובץ סודי להעצמת ביטחון מסד הנתונים. ניתן לחולל קובץ זה מהגדרות אבטחת מסד הנתונים.</p><p>זה <strong>לא</strong> קובץ מסד נתונים *.kdbx. Use hardware key [Serial: %1] @@ -1628,18 +1688,22 @@ To prevent this error from appearing, you must go to "Database Settings / S Your database file is NOT a key file! If you don't have a key file or don't know what that is, you don't have to select one. - + קובץ מסד נתונים הוא לא קובץ מפתח. +אם אין קובץ מפתח או לא ברור מה זה, לא נדרש לקבוע כזה. KeePassXC database file selected - + קובץ מסד נתונים KeePassXC The file you selected looks like a database file. A database file is NOT a key file! Are you sure you want to continue with this file?. - + הקובץ שנבחר נראה כמו קובץ מסד נתונים. +קובץ מסד נתונים הוא לא קובץ מפתח! + +האם להמשיך עם קובץ זה? No hardware keys found. @@ -1649,6 +1713,18 @@ Are you sure you want to continue with this file?. Refresh Hardware Keys רענון מפתחות חומרה + + Click to add a key file. + הקשה להוספת קובץ מפתח חדש. + + + <a href="#" style="text-decoration: underline">I have a key file</a> + <a href="#" style="text-decoration: underline">יש ברשותי קובץ מפתח</a> + + + Hardware keys found, but no slots are configured. + + DatabaseSettingWidgetMetaData @@ -1683,6 +1759,22 @@ Are you sure you want to continue with this file?. Maintenance תחזוקה + + KeeShare + KeeShare + + + Secret Service Integration + שילוב שירות חשאי + + + Remote Sync + סנכרון מרחוק + + + Database Settings: %1 + הגדרות מסד־נתונים: %1 + DatabaseSettingsWidgetBrowser @@ -1853,12 +1945,12 @@ Are you sure you want to continue without a password? ססמה חלשה - You must enter a stronger password to protect your database. - + This is a weak password! For better protection of your secrets, you should choose a stronger password. + זוהי ססמה חלשה! להגנה טובה יותר על קבצים חשאיים נא לבחור בססמה חזקה יותר. - This is a weak password! For better protection of your secrets, you should choose a stronger password. - + The provided password does not meet the minimum quality requirement. + הססמה שסופקה לא עומדת בדרישת האיכות המזערית. @@ -1877,19 +1969,19 @@ Are you sure you want to continue without a password? Database format: - תבנית מסד־נתונים: + תסדיר מסד־נתונים: Database format - תבנית מסד־נתונים + תסדיר מסד־נתונים Format cannot be changed: Your database uses KDBX 4 features - לא ניתן לשנות תבנית: מסד־נתונים משתמש בתכונות KDBX 4 + לא ניתן לשנות תסדיר: מסד־נתונים משתמש בתכונות KDBX 4 Unless you need to open your database with other programs, always use the latest format. - אם את/ה צריכ/ה לפתוח את מסד־נתונים שלך עם תוכנות אחרות, תמיד תשתמש/י בפורמט האחרון (הכי עדכני). + יש להשתמש תמיד תסדיר האחרון (העדכני ביותר). אלא אם יידרש לפתוח את מסד הנתונים גם באמצעות תוכנות אחרות. Encryption Algorithm: @@ -2149,7 +2241,7 @@ removed from the database. Autosave delay since last change in minutes - + השהית שמירה אוטומטית בדקות מאז שינוי אחרון min @@ -2157,6 +2249,50 @@ removed from the database. Autosave delay since last change checkbox + תיבת סימון השהית שמירה אוטומטית בדקות מאז שינוי אחרון + + + Public Database Metadata + + + + Warning: the following settings are not encrypted. + + + + Display name: + שם מצג: + + + Publically visible display name used on the unlock dialog + + + + Database public display name + + + + Display color: + צבע תצוגה: + + + Publically visible color used on the unlock dialog + + + + Database public display color chooser + + + + Clear + נקה + + + Display icon: + סמל תצוגה: + + + Select Database Icon @@ -2254,6 +2390,141 @@ removed from the database. שדה תיאור מסד־נתונים + + DatabaseSettingsWidgetRemote + + Sync Commands + פקודות סנכרון + + + Remove + הסרה + + + Command Settings + הגדרות פקודה + + + Name + שם + + + Save + שמירה + + + Download + הורדה + + + Command: + פקודה: + + + Download command field + הורדת שדה פקודה + + + e.g.: "sftp user@hostname" or "scp user@hostname:DatabaseOnRemote.kdbx {TEMP_DATABASE}" + לדוגמה: "sftp user@hostname" או "scp user@hostname:DatabaseOnRemote.kdbx {TEMP_DATABASE}" + + + Input: + קלט: + + + Download input field + הורדת שדה קלט + + + Upload + האלעה + + + Upload command field + העלאת שדה פקודה + + + e.g.: "sftp user@hostname" or "scp {TEMP_DATABASE} user@hostname:DatabaseOnRemote.kdbx" + לדוגמה: "sftp user@hostname" או "scp {TEMP_DATABASE} user@hostname:DatabaseOnRemote.kdbx" + + + Upload input field + העלאת שדה קלט + + + Name cannot be empty. + שם לא יכול להיות ריק + + + Test + בדיקה + + + Download command cannot be empty. + פקודת הורדה לא יכול להיות ריק + + + Download failed with error: %1 + פקודת הורדה עם שגיאה: %1 + + + Download finished, but file %1 could not be found. + הורדת קבצים שהסתיימו, אבל קובץ %1 לא נמצא. + + + Download successful. + הורדה צלחה. + + + Save Remote Settings + שמירת הגדרות מרוחקות + + + You have unsaved changes. Do you want to save them? + קיימים שינויים שלא נשמרו. האם לשמור אותם? + + + e.g.: +get DatabaseOnRemote.kdbx {TEMP_DATABASE} +exit +--- +{TEMP_DATABASE} is used as placeholder to store the database in a temporary location +The command has to exit. In case of `sftp` as last command `exit` has to be sent + + לדוגמה: +get DatabaseOnRemote.kdbx {TEMP_DATABASE} +exit +--- +{TEMP_DATABASE} משמש כשומר מקום לאחסון מסד הנתונים במיקום זמני. +הפקודה אמורה להסתיים ב'יציאה'. במקרה של `sftp` כפקודה אחרונה, יש לשלוח פקודת `exit` + + + + e.g.: +put {TEMP_DATABASE} DatabaseOnRemote.kdbx +exit +--- +{TEMP_DATABASE} is used as placeholder to store the database in a temporary location +The command has to exit. In case of `sftp` as last command `exit` has to be sent + + לדוגמה: +put {TEMP_DATABASE} DatabaseOnRemote.kdbx +exit +--- +{TEMP_DATABASE} משמש כשומר מקום לאחסון מסד הנתונים במיקום זמני. +הפקודה אמורה להסתיים ב'יציאה'. במקרה של `sftp` כפקודה אחרונה, יש לשלוח פקודת `exit` + + + + Timeout: + + + + seconds + שניות + + DatabaseTabWidget @@ -2327,6 +2598,11 @@ This is definitely a bug, please report it to the developers. Database tab name modifier %1 [נעול] + + %1 [Temporary] + Database tab name modifier + %1 [זמני] + DatabaseWidget @@ -2450,26 +2726,6 @@ Save changes? File has changed הקובץ השתנה - - The database file has changed. Do you want to load the changes? - קובץ מסד־נתונים השתנה. האם לטעון את השינויים? - - - Merge Request - בקשת מיזוג - - - The database file has changed and you have unsaved changes. -Do you want to merge your changes? - קיימים שינויים בקובץ מסד־נתונים שלא נשמרו. -האם למזג את השינויים? - - - Could not open the new database file while attempting to autoreload. -Error: %1 - לא ניתן לפתוח את קובץ מסד־נתונים החדש בעת ניסיון אוטומטית טעינה מחדש . -שגיאה: %1 - Disable safe saves? האם להשבית שמירות בטוחות? @@ -2521,6 +2777,86 @@ Disable safe saves and try again? Database tab name modifier %1 [מסד־נתונים חדש] + + Remote Sync did not contain any download or upload commands. + סנכרון מרוחק לא מכיל הורדה הורדה או העלאה. + + + Remote sync '%1' completed successfully! + סנכרון מרוחק '%1' הושלם בהצלחה! + + + Remote sync '%1' failed: %2 + סנכרון מרוחק '%1' כשל: %2 + + + Error while saving database %1: %2 + שגיאה בעת שמירת מסד נתונים %1: %2 + + + Downloading... + הורדה... + + + Uploading... + מתבצעת העלאה... + + + Syncing... + מתבצע סנכרון... + + + Remove passkey from entry + הסרת Passkey מרשומה + + + Do you want to remove the passkey from this entry? + האם להסיר את ה־Passkey מרשומה זו? + + + The database file "%1" was modified externally + + + + Do you want to load the changes? + + + + Reload database + + + + Reloading database… + + + + Reload canceled + + + + Reload successful + + + + Reload pending user action… + + + + The database file "%1" was modified externally.<br>How would you like to proceed?<br><br>Merge all changes<br>Ignore the changes on disk until save<br>Discard unsaved changes + + + + The database file "%1" was modified externally.<br>How would you like to proceed?<br><br>Merge all changes then save<br>Overwrite the changes on disk<br>Discard unsaved changes + + + + Database file overwritten. + + + + Database file on disk cannot be unlocked with current credentials.<br>Enter new credentials and/or present hardware key to continue. + + EditEntryWidget @@ -2572,10 +2908,6 @@ Disable safe saves and try again? n/a ל/ז - - (encrypted) - (מוצפן) - Select private key בחירת מפתח פרטי @@ -2678,6 +3010,10 @@ Would you like to correct it? %n year(s) שנה %n%n שנים%n שנים + + Failed to decrypt SSH key, ensure password is correct. + פענוח מפתח SSH כשל, נא לוודא שהססמה תקינה. + EditEntryWidgetAdvanced @@ -2849,18 +3185,10 @@ Would you like to correct it? Skip Auto-Submit for this entry דלוג על Auto־Submit ברשומה זו - - Only send this setting to the browser for HTTP Auth dialogs. If enabled, normal login forms will not show this entry for selection. - לשלח הגדרה זו רק לדפדפן עבור דו־שיח HTTP Auth. אם אופשר, טופסי התחברות רגילים לא יציגו רשומה זו לבחירה. - Use this entry only with HTTP Basic Auth נא להשתמש ברשומה זו רק ב־HTTP Basic Auth - - Do not send this setting to the browser for HTTP Auth dialogs. If enabled, HTTP Auth dialogs will not show this entry for selection. - לא לשלח הגדרה זו לדפדפן לדו־שיח HTTP Auth. אם אופשר, דו־שיח HTTP Auth לא יציג רשומה זו לבחירה. - Do not use this entry with HTTP Basic Auth לא להשתמש ברשומה זו ב־HTTP Basic Auth @@ -2879,12 +3207,20 @@ Would you like to correct it? These settings affect the entry's behaviour with the browser extension. - + הגדרות אלו משפיעות על התנהגות הרשומה עם הרחבות הדפדפן. Additional URLs מעני URL נוספים + + Only send this entry to the browser for HTTP Auth dialogs. If enabled, normal login forms will not show this entry for selection. + לשלוח ערך זה לדפדפן רק עבור תיבות דו־שיח HTTP Auth. אם מופעל, טפסי התחברות רגילים לא יציגו ערך זה לבחירה. + + + Do not send this entry to the browser for HTTP Auth dialogs. If enabled, HTTP Auth dialogs will not show this entry for selection. + לא לשלוח ערך זה לדפדפן עבור תיבות דו־שיח של HTTP Auth. אם מופעל, תיבות דו־שיח HTTP Auth לא יציגו ערך זה לבחירה. + EditEntryWidgetHistory @@ -3107,6 +3443,10 @@ Would you like to correct it? seconds שניות + + Clear agent + + EditGroupWidget @@ -3203,7 +3543,7 @@ Would you like to correct it? Restrict matching to given browser key toggle for this and sub groups - + להגביל התאמה כדי לספק מיתוג מפתח דפדפן עבור זה ועבור קבוצות משה. @@ -3471,7 +3811,7 @@ Supported extensions are: %1. You can enable the DuckDuckGo website icon service under Application Settings -> Security - + ניתן לאפשור את שרות סמלי אתר מרשתת DuckDuckGo מתפריט הגדרות יישום -> אבטחה @@ -3549,6 +3889,24 @@ This may cause the affected plugins to malfunction. %1 - Clone שכפול %1 - + + Passkey + Passkey + + + Invalid conversion type: %1 + סוג המרה לא תקין: %1 + + + Invalid conversion syntax: %1 + תחביר המרה לא תקין: %1 + + + Invalid regular expression syntax %1 +%2 + תחביר ביטוי רגיל לא תקין %1 +%2 + EntryAttachments @@ -3557,6 +3915,21 @@ This may cause the affected plugins to malfunction. לא ניתן לפתוח קובץ "%1" + + EntryAttachmentsDialog + + Form + טופס + + + File name + + + + File contents... + + + EntryAttachmentsModel @@ -3594,14 +3967,6 @@ This may cause the affected plugins to malfunction. Remove הסרה - - Rename selected attachment - שנוי שם צרופה שנבחרה - - - Rename - שינוי שם - Open selected attachment פתיחת צרופה שנבחרה @@ -3718,6 +4083,18 @@ Would you like to overwrite the existing attachment? קיימת כבר צרופה "%1". האם לכתוב־על הצרופה הקיימת? + + New + + + + Preview + תצוגה מקדימה + + + Failed to preview an attachment: Attachment not found + + EntryAttributesModel @@ -3916,6 +4293,10 @@ Would you like to overwrite the existing attachment? Background Color צבע רקע + + Group Path + + EntryPreviewWidget @@ -4021,7 +4402,7 @@ Would you like to overwrite the existing attachment? Double click to copy to clipboard - + הקשה כפולה להעתיק ללוח גזירים @@ -4051,7 +4432,7 @@ Would you like to overwrite the existing attachment? + %1 entry(s)... - + רשומה + %1...+ %1 רשומות...+ %1 רשומות... @@ -4312,6 +4693,14 @@ You can enable the DuckDuckGo website icon service in the security section of th Url מען URL + + Could not load key file. + + + + Could not open remote database. Password or key file may be incorrect. + + ImportWizardPageSelect @@ -4345,11 +4734,11 @@ You can enable the DuckDuckGo website icon service in the security section of th No unlocked databases available - + אין מסדי נתונים לא נעולים זמינים Existing Database: - + מסד נתונים קיים: Import File: @@ -4357,23 +4746,23 @@ You can enable the DuckDuckGo website icon service in the security section of th Comma Separated Values (.csv) - + ערכים מופרדים בפסיקים (.csv) 1Password Export (.1pux) - + ייצוא 1Password (.1pux) 1Password Vault (.opvault) - + כספת 1Password (.opvault) Bitwarden (.json) - + Bitwarden (.json) KeePass 1 Database (.kdb) - + מסד נתונים KeePass 1 (.kdb) Open OPVault @@ -4397,22 +4786,60 @@ You can enable the DuckDuckGo website icon service in the security section of th Comma Separated Values - + ערכים מופרדים בפסיקים 1Password Export - + ייצוא 1Password Bitwarden JSON Export - + ייצוא Bitwarden JSON 1Password Vault - + כספת 1Password KeePass1 Database + מסד־נתונים KeePass 1 + + + Proton Pass (.json) + + + + Proton Pass JSON Export + + + + Temporary Database + + + + Command: + פקודה: + + + e.g.: "sftp user@hostname" or "scp user@hostname:DatabaseOnRemote.kdbx {TEMP_DATABASE}" + לדוגמה: "sftp user@hostname" או "scp user@hostname:DatabaseOnRemote.kdbx {TEMP_DATABASE}" + + + Input: + קלט: + + + e.g.: +get DatabaseOnRemote.kdbx {TEMP_DATABASE} +exit +--- +{TEMP_DATABASE} is used as placeholder to store the database in a temporary location +The command has to exit. In case of `sftp` as last commend `exit` has to be sent + + + + + Remote Database (.kdbx) @@ -5102,11 +5529,11 @@ If this reoccurs, then your database file may be corrupt. Old key file format - תבנית קובץ מפתח ישן + תסדיר קובץ מפתח ישן You selected a key file in an old format which KeePassXC<br>may stop supporting in the future.<br><br>Please consider generating a new key file instead. - נבחר קובץ מפתח בתבנית ישנה ש־KeePassXC<br>עשוי להפסיק לתמוך בעתיד.<br><br>במקום זאת, נא לשקול ליצור קובץ מפתח חדש. + נבחר קובץ מפתח בתסדיר ישן ש־KeePassXC<br>עשוי להפסיק לתמוך בעתיד.<br><br>במקום זאת, נא לשקול ליצור קובץ מפתח חדש. Error loading the key file '%1' @@ -5500,7 +5927,7 @@ Are you sure you want to continue with this file? Show Menubar - + הצגת סרגל תפריט Show Toolbar @@ -5555,12 +5982,6 @@ This version is not meant for production use. Expect some bugs and minor issues, this version is meant for testing purposes. הערה: זוהי גרסת טרום שחרור של KeePassXC! צפוי שיתרחשו תקלים וסוגיות קלות, גרסה זו מיועדת לשימוש כמערכת בדיקות. - - - WARNING: Your Qt version may cause KeePassXC to crash with an On-Screen Keyboard. -We recommend you use the AppImage available on our downloads page. - אזהרה: גרסת ה־Qt עלולה לגרום ל־KeePassXC לקרוס בשימוש במקלדת על המסך! -אנו ממליצים להשתמש ב־AppImage הזמין בעמוד ההורדות שלנו. No Tags @@ -5616,11 +6037,11 @@ We recommend you use the AppImage available on our downloads page. 1Password 1PUX... - + 1Password 1PUX... Import a 1Password 1PUX file - + ייבוא קובץ 1Password 1PUX Import… @@ -5634,13 +6055,17 @@ We recommend you use the AppImage available on our downloads page. Import Passkey ייבוא Passkey + + Remote S&ync… + ס&נכרון מרוחק... + Quit Application - + לצאת מהיישומון Open About Dialog - + פתיחת דו־שיח על אודות Open Database @@ -5652,11 +6077,11 @@ We recommend you use the AppImage available on our downloads page. Merge From Database - + למזג ממסד נתונים Create Entry - + יצירת רשומה Edit Entry @@ -5680,47 +6105,47 @@ We recommend you use the AppImage available on our downloads page. Download All Favicons - + הורדת כל הפביקון Sort Groups A-Z - + סינון קבוצות א–ת Sort Groups Z-A - + סינון קבוצות ת–א Save Database As - + שמירת מסד נתונים בשם Show Database Security - + הצגת אבטחת מסד נתונים Show Database Reports - + הצגת דוחות מסד נתונים Show Database Settings - + הצגת הגדרות מסד נתונים Show Passkeys - + הצגת Passkeys Clone Entry - + שכפול רשומה Move Entry Up - + העברת רשומה מעלה Move Entry Down - + העברת רשומה מטה Copy Username @@ -5732,51 +6157,55 @@ We recommend you use the AppImage available on our downloads page. Show Application Settings - + הצגת הגדרות יישום Show Password Generator - + הצגת מחולל ססמאות + + + Remove Passkey From Entry + הסרת Passkey מרשומה Perform Auto-Type: {USERNAME} - + ביצוע הקלדה אוטומטית: {USERNAME} Perform Auto-Type: {USERNAME}{ENTER} - + ביצוע הקלדה אוטומטית: {USERNAME}{ENTER} Perform Auto-Type: {PASSWORD} - + ביצוע הקלדה אוטומטית: {PASSWORD} Perform Auto-Type: {PASSWORD}{ENTER} - + ביצוע הקלדה אוטומטית: {PASSWORD}{ENTER} Perform Auto-Type: {TOTP} - + ביצוע הקלדה אוטומטית: {TOTP} Copy Title - + להעתיק תואר Copy URL - + להעתיק מען URL Copy Notes - + להעתיק הערות Export to CSV - + ייצוא ל־CSV Export to HTML - + ייצוא ל־HTML Import KeePass1 Database @@ -5784,102 +6213,130 @@ We recommend you use the AppImage available on our downloads page. Import 1Password Vault - + ייבוא כספת 1Password Import CSV File - + ייבוא קובץ CSV Show TOTP QR Code - + הצגת קוד QR TOTP Set up TOTP - + הגדרת TOTP Empty Recycle Bin - + לרוקן סל מחזור Open Donation Website - + לפתוח אתר מרשתת תרומה Open Bug Report - + לפתוח דוח תקלים Open Online Documentation - + לפתוח תיעוד מקוון Open Keyboard Shortcuts Guide - + לפתוח מדריך קיצורי־דרך מקלדת Save Database Backup - + לשמור גיבוי מסד נתונים SSH Agent: Add Key - + סוכן SSH: הוספת מפתח SSH Agent: Remove Key - + סוכן SSH: הסרת מפתח Toggle Compact Mode - + מיתוג מצב צמום Set Theme: Automatic - + קביעת ערכת נושא באופן אוטומטי Set Theme: Light - + קביעת ערכת נושא: בהירה Set Theme: Dark - + קביעת ערכת נושא: כהה Set Theme: Classic - + קביעת ערכת נושא: קלאסי Toggle Show Menubar - + מיתוג הצגת סרגל תפריט Toggle Show Toolbar - + מיתוג הצגת סרגל כלים Toggle Show Preview Panel - + מיתוג הצגת לוח תצוגה מקדימה Toggle Always on Top - + מיתוג תמיד עליון Toggle Hide Usernames - + מיתוג הסתרת שם משתמש Toggle Hide Passwords - + מיתוג הסתרת ססמאות Export to XML - + ייצוא ל־XML Toggle Allow Screen Capture + מיתוג אפשור לכידת מרקע + + + Show Group Panel + + + + Toggle Show Group Panel + + + + Setup Remote Sync… + הגדרת סנכרון מרוחק... + + + Password Generator + + + + E&xpire Entry… + + + + Clear SSH Agent + + + + Clear all identities in ssh-agent @@ -6032,6 +6489,25 @@ We recommend you use the AppImage available on our downloads page. נא להזין את שם המצג ותיאור חלופי למסד־נתונים החדש: + + NewEntryAttachmentsDialog + + Attachment name cannot be empty + + + + Attachment with the same name already exists + + + + Save attachment + + + + New entry attachment + + + NixUtils @@ -6219,6 +6695,10 @@ We recommend you use the AppImage available on our downloads page. Unexpected EOF when writing private key EOF לא צפוי בעת כתיבת מפתח פרטי + + (encrypted) + (מוצפן) + OpenSSHKeyGenDialog @@ -6243,19 +6723,19 @@ We recommend you use the AppImage available on our downloads page. PasskeyExportDialog KeePassXC - Passkey Export - + ייצוא KeePassXC – Passkey Filenames will be generated with title and .passkey file extension. - + שמות קבצים יחוללו עם כותרת וסיומת קובץ Passkey. Export entries - + ייצוא רשומות Export Selected - + ייצוא בחירה Cancel @@ -6263,43 +6743,44 @@ We recommend you use the AppImage available on our downloads page. Export to folder - + ייצוא לתיקייה Export the following passkey entries. - + ייצוא רשומות ה־Passkey הבאות. PasskeyExporter KeePassXC: Passkey Export - + KeePassXC: ייצוא Passkey File "%1.passkey" already exists. Do you want to overwrite it? - + קובץ "%1.passkey" כבר קיים +האם לכתוב עליו? Cannot open file - + לא ניתן לפתוח קובץ Cannot open file "%1" for writing. - + לא ניתן לפתוח קובץ "%1" לכתיבה. Cannot write to file - + לא ניתן לכתוב לקובץ PasskeyImportDialog KeePassXC - Passkey Import - + ייבוא KeePassXC – Passkey Username: %1 @@ -6311,7 +6792,7 @@ Do you want to overwrite it? Database - + Database Import Passkey @@ -6331,30 +6812,30 @@ Do you want to overwrite it? Create new entry - + יצירת רשומה חדשה Relying Party: %1 - + צד סומך: %1 Import the following passkey: - + ייבוא ה־ הבא:Passkey Import the following passkey to this entry: - + לייבא את ה־Passkey הבא לרשומה זו: Default passkeys group (Imported Passkeys) - + קבוצה passkeys בררת מחדל (passkeys שיובאו) PasskeyImporter Passkey file - + קובץ Passkey All files @@ -6362,33 +6843,35 @@ Do you want to overwrite it? Cannot open file - + לא ניתן לפתוח קובץ Cannot open file "%1" for reading. - + לא ניתן לפתוח קובץ "%1" לקריאה. Open passkey file - + פתיחת קובץ Passkey Cannot import passkey - + לא ניתן לייבוא Passkey Cannot import passkey file "%1". Data is missing. - + לא ניתן לייבוא קובץ Passkey "%1". חסרים נתונים. Cannot import passkey file "%1". The following data is missing: %2 - + לא ניתן לייבא קובץ Passkey "%1". +הנתון הבא חסר: +%2 Cannot import passkey file "%1". Private key is missing or malformed. - + לא ניתן לייבא קובץ Passkey "%1". מפתח פרטי חסר או לוקה בתצורה. @@ -6569,10 +7052,6 @@ The following data is missing: Also choose from: נא לבחור גם מבין: - - Excluded characters: "0", "1", "l", "I", "O", "|", "﹒" - תווים שהוחרגו: "0", "O", "1", "l", "I", "|", "G", "6", "B", "8", "." - Exclude look-alike characters החרגת תווים דומים @@ -6597,10 +7076,6 @@ The following data is missing: Word Count: ספירת מילים: - - Character Count: - ספירת תווים: - Word Case: גודל אות: @@ -6613,10 +7088,6 @@ The following data is missing: Add custom wordlist הוספת רשימת־מילים מותאמת אישית - - character - תו - Close סגירה @@ -6723,6 +7194,22 @@ Do you want to overwrite it? Special Characters תווים מיוחדים + + passwordLength + אורך ססמה + + + Characters: %1 + תווים: %1 + + + MIXED case + + + + Excluded characters: "0", "1", "l", "I", "O", "|", "﹒", "B", "8", "G", "6" + + PasswordWidget @@ -6772,7 +7259,7 @@ Do you want to overwrite it? Toggle password visibility using Control + H. Open the password generator using Control + G. - + מיתוג נראות ססמה תוך שימוש ב'קונטרול + H'. פתיחת מחולל ססמאות תוך שימוש ב'קונטרול + G'. @@ -6790,6 +7277,21 @@ Do you want to overwrite it? הקשה על &Tab בין תווים + + PreviewEntryAttachmentsDialog + + Preview entry attachment + + + + No preview available + + + + Image format not supported + + + QMessageBox @@ -6830,7 +7332,7 @@ Do you want to overwrite it? Continue with weak password - + להמשיך עם ססמה חלשה @@ -6993,7 +7495,7 @@ Do you want to overwrite it? Check if any passwords have been publicly leaked. FILENAME must be the path of a file listing SHA-1 hashes of leaked passwords in HIBP format, as available from https://haveibeenpwned.com/Passwords. - נא לבדוק אם ססמאות כלשהן הודלפו בפומבי. FILENAME חייב להיות הנתיב של קובץ המפרט HASS SHA־1 של ססמאות שדלפו בתבנית HIBP, כפי שזמין ב־https://haveibeenpwned.com/Passwords. + נא לבדוק אם ססמאות כלשהן הודלפו בפומבי. FILENAME חייב להיות הנתיב של קובץ המפרט HASS SHA־1 של ססמאות שדלפו בתסדיר HIBP, כפי שזמין ב־https://haveibeenpwned.com/Passwords. FILENAME @@ -7468,10 +7970,6 @@ Do you want to overwrite it? Invalid word count %1 ספירת מילים לא תקינה %1 - - The word list is too small (< 1000 items) - רשימת המילים קטנה מדי (< 1000 פריטים) - Title for the entry. כותרת הרשומה. @@ -7616,13 +8114,9 @@ Do you want to overwrite it? Exit interactive mode. יציאה ממצב הידודי. - - Format to use when exporting. Available choices are 'xml' or 'csv'. Defaults to 'xml'. - תבנית לשימוש בעת ייצוא. האפשרויות הזמינות הן 'xml' או 'csv'. ברירת המחדל היא 'xml'. - Exports the content of a database to standard output in the specified format. - ייצוא תוכן מסד־נתונים לפלט רגיל בתבנית שצוינה. + ייצוא תוכן מסד־נתונים לפלט רגיל בתסדיר שצוין. Unable to export database to XML: %1 @@ -7630,7 +8124,7 @@ Do you want to overwrite it? Unsupported format %1 - תבנית %1 לא נתמכת + תסדיר %1 לא נתמך Length of the generated password @@ -7953,7 +8447,7 @@ Available commands: stop supporting in the future. Please consider generating a new key file. - אזהרה: נעשה שימוש בתבנית קובץ מפתח ישנה ש־KeePassXC עשוי + אזהרה: נעשה שימוש בתסדיר קובץ מפתח ישן ש־KeePassXC עשוי להפסיק לתמוך בעתיד. נא לשקול ליצור קובץ מפתח חדש. @@ -8207,18 +8701,6 @@ Kernel: %3 %4 file empty קובץ ריק - - malformed string - מחרוזת פגומה - - - missing closing quote - חסרה מרכאה סוגרת - - - %1: (row, col) %2,%3 - %1: (שורה, עמודה) %2,%3 - AES 256-bit AES- 256 סיביות @@ -8457,40 +8939,41 @@ Kernel: %3 %4 allow screenshots and app recording (Windows/macOS) - + אפשור תצלום מצג והקלטת יישום Iוינדוס/מאק OS) Set the key file for the database. This option is deprecated, use --set-key-file instead. - + קביעת קובץ המפתח למסד הנתונים. +אפשרות זו הוצאה משימוש, במקום זאת יש להשתמש ב: ' --set-key-file'. Databases have been locked. - + מסד נתונים ננעל. Attestation not supported - + אימות לא נתמך Credential is excluded - + נתוני אמנה הוחרגו Passkeys request canceled - + בקשת Passkeys בוטלה Invalid user verification - + אימות משתמש לא תקין Empty public key - + מפתח ציבורי ריק Invalid URL provided - + סופק מען URL לא תקין Passkeys @@ -8498,43 +8981,43 @@ This option is deprecated, use --set-key-file instead. AES initialization failed - + אתחול AES כשל AES encrypt failed - + הצפנת AES כשלה Failed to store in Linux Keyring - + אחסון ב־Keyring לינוקס כשל Polkit returned an error: %1 - + Polkit החזיר שגיאה: %1 Could not locate key in keyring - + לא ניתן לאתר מפתח ב־keyring Could not read key in keyring - + לא ניתן לקרוא מפתח ב־keyring AES decrypt failed - + פענוח AES כשל No Polkit authentication agent was available - + סוכן אימות Polkit לא זמין Polkit authorization failed - + הרשאת Polkit כשלה No Quick Unlock provider is available - + ספק שרות שחרור נעילה מהיר לא זמין Failed to init KeePassXC crypto. @@ -8554,122 +9037,198 @@ This option is deprecated, use --set-key-file instead. Origin is empty or not allowed - + מקור ריק או לא מאופשר Effective domain is not a valid domain - + התחום בפועל אינן תחום תקין Origin and RP ID do not match - + מקור ומזהה RP לא תואמים No supported algorithms were provided - + לא סופק אלגוריתם נתמך Wait for timer to expire - + המתנה לתפוגת קוצב זמן Challenge is shorter than required minimum length - + אתגר מענה קצר מאורך מזערי נדרש user.id does not match the required length - + מזהה משתמש לא תואם לאורך הנדרש Favorite Tag for favorite entries - + מועדף File does not exist. - + קובץ לא קיים. Cannot open file: %1 - + לא ניתן לפתוח קובץ: %1 Cannot parse file: %1 at position %2 - + לא ניתן לפרק קובץ: %1 באיות %2 Failed to decrypt json file: %1 - + פענוח קובץ json כשל: %1 Invalid encKeyValidation field - + שדה encKeyValidation לא תקין Invalid cipher list within encKeyValidation field - + רשימת צופן בתוך שדה צופן encKeyValidation לא תקינה Wrong password - + ססמה שגויה Invalid encrypted data field - + שדה נתונים מוצפן לא תקין Invalid cipher list within encrypted data field - + רשימה צופן בתוך שדה נתונים מוצפן לא תקין Cannot initialize cipher - + לא ניתן לאתחל צופן Cannot decrypt data - + לא ניתן לפענח נתונים Bitwarden Import - + ייבוא Bitwarden Archived Tag for archived entries - + הועבר לארכיון Invalid 1PUX file format: Not a valid ZIP file. - + תסדיר קובץ 1PUX לא תקין: לא קובץ ZIP תקין. Invalid 1PUX file format: Missing export.data - + תסדיר קובץ 1PUX לא תקין: נתוני ייצוא חסרים 1Password Import - + 1Password יובא Enter Shortcut - + הזנת קיצור־דרך Action - + פעולה Shortcuts - - - - Unsupported KDF type, cannot decrypt json file - + קיצורי־דרך Unknown passkeys error + שגיאת passkeys לא ידועה + + + Invalid KDF iterations, cannot decrypt json file + חזרורי KDF לא תקינים, לא ניתן לפענח קובץ json + + + Unsupported format, ensure your Bitwarden export is password-protected + תסדיר לא נתמך, נא לוודא שייצוא Bitwarden מוגן בססמה + + + Only PBKDF and Argon2 are supported, cannot decrypt json file + רק PBKDF ו־Argon2 נתמכים, לא ניתן לפענח קובץ json + + + Reset Shortcuts + שיצוב קיצורי־דרך + + + Double click an action to change its shortcut + הקשה כפולה על פעולה לשינוי קיצור הדרך שלה + + + Filter... + סינון... + + + Shortcut Conflict + התנגשות קיצור־דרך + + + Shortcut %1 conflicts with '%2'. Overwrite shortcut? + קיצור־דרך %1 מתנגש עם %2'. לכתוב על קיצור־הדרך? + + + Cannot generate valid passphrases because the wordlist is too short + לא ניתן לחולל ביטוי סיסמה תקין מכיוון שרשימת המילים קצרה מדי + + + Encrypted files are not supported. + + Proton Pass Import + + + + Delete plugin data? + האם למחוק נתוני מתקע? + + + Delete plugin data from Entry(s)? + מחיקת נתוני מתקע מרשומות?מחיקת נתוני מתקע מרשומות?מחיקת נתוני מתקע מרשומה? + + + Passkey + Passkey + + + Format to use when exporting. Available choices are 'xml', 'csv' or 'html'. Defaults to 'xml'. + + + + start minimized to the system tray + + + + malformed string, possible unescaped delimiter + + + + missing closing delimiter + + + + %1, row: %2, column: %3 + + + + Tags + תגים + QtIOCompressor @@ -8698,13 +9257,44 @@ This option is deprecated, use --set-key-file instead. QtIOCompressor::open The gzip format not supported in this version of zlib. - תבנית gzip אינה נתמכת בגרסה זו של zlib. + תסדיר gzip אינו נתמך בגרסה זו של zlib. Internal zlib error: שגיאת zlib פנימית: + + RemoteHandler + + Command `%1` did not finish in time. Process was killed. + פקודה `%1` לא הסתיימה בזמן. תהליך חוסל. + + + Failed to upload merged database. Command `%1` did not finish in time. Process was killed. + העלאת מסד נתונים שמוזג כשל. פקודה `%1` לא הסתיימה בזמן. תהליך חוסל. + + + Invalid download parameters provided. + סופקו פרמטרי הורדה לא תקינים. + + + Command `%1` failed to download database. + פקודה `%1` כשלה בהורדת מסד נתונים. + + + Invalid database pointer or upload parameters provided. + סופקו מצביעי מסד נתונים או פרמטרי העלאה לא תקינים. + + + Command `%1` exited with status code: %2 + פקודה `%1` יצאה עם קוד מצב: %2 + + + Failed to upload merged database. Command `%1` exited with status code: %2 + העלאת מסד נתונים שמוזג כשלה. פקודה `%1` יצאה עם קוד מצב: %2 + + ReportsWidgetBrowserStatistics @@ -8771,52 +9361,53 @@ This option is deprecated, use --set-key-file instead. Exclude from reports החרגה מדוחות + + Expire Entry(s)… + + Only show entries that have a URL - + להציג רק רשומות שיש להן מען URL Only show entries that have been explicitly allowed or denied - + להציג רק רשומות שאפשרו או נדחו במפורש Show expired entries - + הצגת רשומות שפגו (Expired) (פג) + + Delete plugin data from Entry(s)… + מחיקת נתוני מתקע מרשומות?מחיקת נתוני מתקע מרשומות?מחיקת נתוני מתקע מרשומה? + ReportsWidgetHealthcheck - Hover over reason to show additional details. Double-click entries to edit. - ריחוף מעל סיבה להצגת פרטים נוספים. הקשה כפולה על רשומות לעריכה. + Show expired entries + הצגת רשומות שפגו - Bad - Password quality - רע + (Expired) + (פג) + + + Hover over reason to show additional details. Double-click entries to edit. + ריחוף מעל סיבה להצגת פרטים נוספים. הקשה כפולה על רשומות לעריכה. Bad — password must be changed חלש — יש לשנות ססמה - - Poor - Password quality - עלוב - Poor — password should be changed חלש — יש לשנות ססמה - - Weak - Password quality - חלש - Weak — consider changing the password חלש — נא לשקול לשנות הססמה @@ -8865,17 +9456,13 @@ This option is deprecated, use --set-key-file instead. Exclude from reports החרגה מדוחות - - Show expired entries - + + Expire Entry(s)… + Show entries that have been excluded from reports - - - - (Expired) - (פג) + הצגת רשומות שהוחרגו מדוחות @@ -8972,6 +9559,10 @@ This option is deprecated, use --set-key-file instead. Exclude from reports החרגה מדוחות + + Expire Entry(s)… + + ReportsWidgetPasskeys @@ -9013,11 +9604,11 @@ This option is deprecated, use --set-key-file instead. Relying Party - + צד נסמך Show expired entries - + הצגת רשומות שפגו (Expired) @@ -9029,15 +9620,16 @@ This option is deprecated, use --set-key-file instead. The passkey file will be vulnerable to theft and unauthorized use, if left unsecured. Are you sure you want to continue? - + קובץ ה־Passkey יהיה פגיע לגנבה או שימוש לא מאושר.האם להמשיך? Please wait, list of entries with passkeys is being updated… - + נא להמתין, מתבצעת העלאת רשימת רשומות עם passkeys +... No entries with passkeys. - + אין רשומות עם passkeys. @@ -9213,6 +9805,14 @@ This option is deprecated, use --set-key-file instead. No agent running, cannot list identities. אין סוכן פעיל, לא ניתן להוסיף זהויות. + + Failed to remove all SSH identities from agent. + + + + All SSH identities removed from agent. + + SearchHelpWidget @@ -9387,11 +9987,11 @@ This option is deprecated, use --set-key-file instead. <html><head/><body><p>This setting does not override disabling recycle bin prompts </p></body></html> - + <html><head/><body><p>הגדרה זו does not לא עוקפת השבתת השבתת הנחיות סל מחזור </p></body></html> <html><head/><body><p>This improves compatibility with certain applications which search for password without unlocking the database first.</p><p>But enabling this may also crash the client if the database can not be unlocked within a certain timeout. (Usually 25s, but may be a different value set in applications.) </p></body></html> - + <html><head/><body><p>משפר תאימות עם יישומים מסוימים שמחפשים ססמה מבלי לשחרר את נעילת מסד הנתונים תחילה.</p><p>אבל הפעלת אפשרות זו עשויה גם לגרום ללקוח לקרוס אם נעילת מסד הנתונים ישתחרר בתוך פרק זמן מסוים. (בדרך כלל 25 שניות, אך עשוי להיות ערך שונה שהוגדר ביישומים.) </p></body></html> @@ -9498,29 +10098,6 @@ This option is deprecated, use --set-key-file instead. ייצוא ל־%1 - - ShortcutSettingsWidget - - Double click an action to change its shortcut - - - - Shortcut Conflict - - - - Filter... - - - - Shortcut %1 conflicts with '%2'. Overwrite shortcut? - - - - Reset Shortcuts - - - TagModel @@ -9606,7 +10183,7 @@ This option is deprecated, use --set-key-file instead. Secret key must be in Base32 format - מפתח סודי חייב להיות בתבנית Base32 + מפתח סודי חייב להיות בתסדיר Base32 Secret key field @@ -9660,7 +10237,7 @@ This option is deprecated, use --set-key-file instead. You have entered an invalid secret key. The key must be in Base32 format. Example: JBSWY3DPEHPK3PXP - הוזן מפתח סודי לא תקין. המפתח חייב להיות בתבנית Base32. + הוזן מפתח סודי לא תקין. המפתח חייב להיות בתסדיר Base32. דוגמה: JBSWY3DPEHPK3PXP @@ -9810,12 +10387,16 @@ Example: JBSWY3DPEHPK3PXP לא זוהה מפתח חומרה - <p>If you own a <a href="https://www.yubico.com/">YubiKey</a> or <a href="https://onlykey.io">OnlyKey</a>, you can use it for additional security.</p><p>The key requires one of its slots to be programmed as <a href="https://docs.yubico.com/yesdk/users-manual/application-otp/challenge-response.html">HMAC-SHA1 Challenge-Response</a>.</p> + Refresh hardware keys + רענון מפתחות חומרה + + + <p>If you own a <a href="https://www.yubico.com/">YubiKey</a> or <a href="https://onlykey.io">OnlyKey</a>, you can use it for additional security.</p><p>The key requires one of its slots to be programmed with <a href="https://keepassxc.org/docs/#faq-yubikey-howto">Challenge-Response</a>.</p> - Refresh hardware keys - רענון מפתחות חומרה + Hardware keys found, but no slots are configured + @@ -9843,7 +10424,7 @@ Example: JBSWY3DPEHPK3PXP (NFC) %1 [%2] - Slot %3, %4 YubiKey display fields - + (NFC) %1 [%2] - חריץ %3, %4 Press @@ -9895,12 +10476,12 @@ Example: JBSWY3DPEHPK3PXP %1 [%2] - Slot %3 YubiKey NEO display fields - + %1 [%2] - חריץ %3 %1 [%2] - Slot %3, %4 YubiKey display fields - + %1 [%2] - חריץ %3, %4 \ No newline at end of file diff --git a/share/translations/keepassxc_hr.ts b/share/translations/keepassxc_hr.ts index 7f44a1e6b..417c7a362 100644 --- a/share/translations/keepassxc_hr.ts +++ b/share/translations/keepassxc_hr.ts @@ -150,10 +150,6 @@ SSH Agent connection is working! SSH Agent veza radi! - - Use both agents - - ApplicationSettingsWidget @@ -225,10 +221,6 @@ Select backup storage directory - - This setting cannot be enabled when minimize on unlock is enabled. - - ApplicationSettingsWidgetGeneral @@ -497,14 +489,6 @@ Remember last typed entry for: - - recent files - - - - Show passwords in color - - ApplicationSettingsWidgetSecurity @@ -654,10 +638,6 @@ Invalid placeholder: %1 - - Entry does not have attribute for PICKCHARS: %1 - - AutoTypeAssociationsModel @@ -1437,6 +1417,10 @@ Sigurnosna kopija baza podataka nalazi se na %2 Key File: Datoteka ključa: + + <p>In addition to a password, you can use a secret file to enhance the security of your database. This file can be generated in your database's security settings.</p><p>This is <strong>not</strong> your *.kdbx database file!<br>If you do not have a key file, leave this field empty.</p><p>Click for more information…</p> + + Key file help Datoteka ključa pomoć @@ -1449,6 +1433,11 @@ Sigurnosna kopija baza podataka nalazi se na %2 Hardware Key: Hardverski ključ: + + <p>You can use a hardware security key such as a <strong>YubiKey</strong> or <strong>OnlyKey</strong> with slots configured for HMAC-SHA1.</p> +<p>Click for more information…</p> + + Hardware key help Hardverski ključ pomoć @@ -1584,15 +1573,6 @@ Ako nemate datoteku ključa, ostavite polje prazno. Select hardware key… Odaberite hardverski ključ... - - <p>In addition to a password, you can use a secret file to enhance the security of your database. This file can be generated in your database's security settings.</p><p>This is <strong>not</strong> your *.kdbx database file!<br>If you do not have a key file, leave this field empty.</p><p>Click for more information…</p> - - - - <p>You can use a hardware security key such as a <strong>YubiKey</strong> or <strong>OnlyKey</strong> with slots configured for HMAC-SHA1.</p> -<p>Click for more information…</p> - - DatabaseSettingWidgetMetaData @@ -2239,21 +2219,13 @@ Ovo je definitivno pogreška, molimo prijavite to programerima. Database tab name modifier %1 [Zaključano] - - Export database to XML file - - - - XML file - - - - Writing the XML file failed - - DatabaseWidget + + Database Tags + + Searching… @@ -2418,22 +2390,6 @@ Disable safe saves and try again? Entries expiring within %1 day(s) - - Searches and Tags - - - - Enter a unique name or overwrite an existing search from the list: - - - - Save - Spremi - - - Save Search - - EditEntryWidget @@ -2570,6 +2526,10 @@ Would you like to correct it? Hide Sakrij + + Tomorrow + Sutra + %n week(s) %n tjedan%n tjedana%n tjedana @@ -2582,10 +2542,6 @@ Would you like to correct it? %n year(s) %n godina%n godine%n godina - - %n hour(s) - - EditEntryWidgetAdvanced @@ -3101,14 +3057,6 @@ Would you like to correct it? Do not use HTTP Auth toggle for this and sub groups - - Omit WWW subdomain from matching: - - - - Omit WWW subdomain from matching toggle for this and sub groups - - EditGroupWidgetKeeShare @@ -3690,10 +3638,6 @@ Error: %1 Auto-Type Auto-tipkanje - - Tags - - EntryModel @@ -3901,10 +3845,6 @@ Error: %1 Disabled Onemogući - - Double click to copy value - - EntryURLModel @@ -5389,30 +5329,6 @@ We recommend you use the AppImage available on our downloads page. You must restart the application to apply this setting. Would you like to restart now? Morate ponovno pokrenuti aplikaciju da biste primijenili tu postavku. Želite li ju ponovno pokrenuti sada? - - Tags - - - - No Tags - - - - %1 Entry(s) - - - - Copy Password and TOTP - - - - &XML File… - - - - XML File… - - ManageDatabase @@ -5783,6 +5699,29 @@ We recommend you use the AppImage available on our downloads page. + + PasswordEdit + + Passwords do not match + Lozinke se ne podudaraju + + + Passwords match so far + Lozinke se zasad podudaraju + + + Toggle Password (%1) + + + + Generate Password (%1) + Proizvedi Lozinku (%1) + + + Warning: Caps Lock enabled! + Upozorenje: Caps Lock uključen! + + PasswordEditWidget @@ -5961,6 +5900,10 @@ We recommend you use the AppImage available on our downloads page. Also choose from: + + Excluded characters: "0", "1", "l", "I", "O", "|", "﹒" + Izostavi znakove: "0", "1", "l", "I", "O", "|", "". + Exclude look-alike characters Izostavi slične znakove @@ -6110,57 +6053,6 @@ Do you want to overwrite it? Password quality Izvrsna - - Excluded characters: "0", "1", "l", "I", "O", "|", "﹒" - Izostavi znakove: "0", "1", "l", "I", "O", "|", "". - - - - PasswordWidget - - Passwords do not match - Lozinke se ne podudaraju - - - Passwords match so far - Lozinke se zasad podudaraju - - - Toggle Password (%1) - - - - Generate Password (%1) - Proizvedi Lozinku (%1) - - - Warning: Caps Lock enabled! - Upozorenje: Caps Lock uključen! - - - Quality: %1 - - - - Poor - Password quality - bijedna - - - Weak - Password quality - Slaba - - - Good - Password quality - Dobra - - - Excellent - Password quality - Izvrsna - PickcharsDialog @@ -7293,6 +7185,10 @@ Please consider generating a new key file. Invalid YubiKey serial %1 + + Please present or touch your YubiKey to continue… + + Enter password to encrypt database (optional): @@ -7768,67 +7664,6 @@ Kernel: %3 %4 Failed to sign challenge using Windows Hello. - - Please present or touch your YubiKey to continue. - - - - Show all the attributes of the entry. - - - - Edit a database. - - - - Could not change the database key. - - - - Database was not modified. - - - - Successfully edited the database. - - - - Loading the new key file failed: %1 - - - - Unset the password for the database. - - - - Unset the key file for the database. - - - - Cannot use %1 and %2 at the same time. - - - - Cannot remove all the keys from a database. - - - - Cannot remove password: The database does not have a password. - - - - Cannot remove file key: The database does not have a file key. - - - - Found unexpected Key type %1 - - - - Set the key file for the database. -This options is deprecated, use --set-key-file instead. - - QtIOCompressor @@ -8376,10 +8211,6 @@ This options is deprecated, use --set-key-file instead. Limit search to selected group - - Save Search - - SettingsClientModel @@ -8592,6 +8423,10 @@ This options is deprecated, use --set-key-file instead. TagModel + + All + + Expired @@ -8600,33 +8435,6 @@ This options is deprecated, use --set-key-file instead. Weak Passwords - - All Entries - - - - Clear Search - - - - - TagView - - Remove Search - - - - Remove Tag - - - - Confirm Remove Tag - - - - Remove tag "%1" from all entries in this database? - - TotpDialog diff --git a/share/translations/keepassxc_hu.ts b/share/translations/keepassxc_hu.ts index c1840c418..c61e1bf6c 100644 --- a/share/translations/keepassxc_hu.ts +++ b/share/translations/keepassxc_hu.ts @@ -217,18 +217,50 @@ You must restart the application to set the new language. Would you like to restart now? Az új nyelv beállításának érvényesítéséhez újra kell indítani az alkalmazást. Indítsuk újra most? - - Reset Settings? - Beállítások visszaállítása? - - - Are you sure you want to reset all general and security settings to default? - Biztos, hogy vissza akarja állítani az összes általános és biztonsági beállítást az alapértelmezésre? - Select backup storage directory Válassza ki a biztonsági mentés könyvtárát. + + Confirm Reset + Visszaállítás megerősítése + + + Are you sure you want to reset all settings to default? + Valóban visszaállítja az összes beállítást az alapértelmezésre? + + + Import KeePassXC Settings + KeePassXC-beállítások importálása + + + Failed to import settings from %1, not a valid settings file. + A beállítások importálása sikertelen, mivel a beállításfájl nem érvényes: %1. + + + Export KeePassXC Settings + KeePassXC-beállítások exportálása + + + Small + Kicsi + + + Normal + Normál + + + Medium + Közepes + + + Large + Nagy + + + Custom + Egyéni + ApplicationSettingsWidgetGeneral @@ -280,25 +312,6 @@ Include beta releases when checking for updates A frissítések keresése a béta kiadásokra is terjedjen ki - - On database unlock, show entries that - Az adatbázis feloldásakor azon bejegyzések megjelenítése, amelyek - - - have expired - On database unlock, show entries that... - lejártak - - - days - On database unlock, show entries that will expire within %1 days - napon belül - - - will expire within - On database unlock, show entries that... - lejárnak - File Management Fájlkezelés @@ -323,22 +336,10 @@ Backup database file before saving Készüljön biztonsági mentés az adatbázisról mentés előtt - - Backup destination - Biztonsági mentés célja - - - Specifies the database backup file location. Occurrences of "{DB_FILENAME}" are replaced with the filename of the saved database without extension. {TIME:<format>} is replaced with the backup time, see https://doc.qt.io/qt-5/qdatetime.html#toString. <format> defaults to format string "dd_MM_yyyy_hh-mm-ss". - Megadja az adatbázis biztonsági mentési fájljának helyét. A „{DB_FILENAME}” le lesz cserélve a mentett adatbázis nevére, kiterjesztés nélkül. A {TIME:<formátum>} le lesz cserélve a biztonsági mentés idejére, lásd a következő oldalt: https://doc.qt.io/qt-5/qdatetime.html#toString. A <formátum> alapértelmezett értéke „dd_MM_yyyy_hh-mm-ss”. - {DB_FILENAME}.old.kdbx {DB_FILENAME}.old.kdbx - - Choose... - Válasszon… - Use alternative saving method (may solve problems with Dropbox, Google Drive, GVFS, etc.) Alternatív mentési módszer alkalmazása (megoldhatja a Dropbox, Google Drive, GVFS, stb. mentési problémákat) @@ -505,6 +506,71 @@ Remember last typed entry for: Utolsó beírt bejegyzés megjegyzése ehhez: + + On database unlock, show entries that will expire within + Az ennyi időn belül lejáró bejegyzések megjelenítése az adatbázis feloldásakor: + + + On database unlock, show entries that will expire within + Az ennyi időn belül lejáró bejegyzések megjelenítése az adatbázis feloldásakor: + + + days + number of days warning for password expiration + napon belül + + + Destination format: + Célformátum: + + + <html><head/><body><p><span style=" font-weight:600;">{DB_FILENAME}</span> is replaced with the filename of the saved database without extension</p><p><span style=" font-weight:600;">{TIME:&lt;format&gt;}</span> is replaced with the specified time format (default: dd_MM_yyyy_hh-mm-ss)</p><p>See the User Guide for more details</p></body></html> + <html><head/><body><p>A <span style=" font-weight:600;">{DB_FILENAME}</span> le lesz cserélve a mentett adatbázis kiterjesztés nélküli nevére</p><p>A <span style=" font-weight:600;">{TIME:&lt;format&gt;}</span> le lesz cserélve a megadott időformátumra (alapértelmezés: dd_MM_yyyy_hh-mm-ss)</p><p>További részletekért lásd a felhasználói útmutatót</p></body></html> + + + Choose folder... + Válasszon mappát… + + + Show confirmation before moving entries to recycle bin + Megerősítés megjelenítése a bejegyzések kukába dobása előtt + + + Copy data on double clicking field in entry view + Adatok másolása a mezőre való dupla kattintásra bejegyzésnézetben + + + Show toolbar + Eszköztár megjelenítése + + + Show the menu bar by pressing the Alt key + A menü megjelenítése az Alt gomb lenyomásakor + + + Show menubar + Menü megjelenítése + + + Import settings… + Beállítások importálása… + + + Export settings… + Beállítások exportálása… + + + Open browser on double clicking URL field in entry view + Böngésző megnyitása az URL mezőre való dupla kattintásra bejegyzésnézetben + + + Font size: + Betűméret: + + + Font size selection + Betűméret kijelölése + ApplicationSettingsWidgetSecurity @@ -570,18 +636,6 @@ Hide passwords in the entry preview panel Jelszavak elrejtése a bejegyzés előnézeti panelen - - Hide entry notes by default - Bejegyzések jegyzeteinek elrejtése alapértelmezetten - - - Move entries to recycle bin without confirmation - Bejegyzések kukába dobása megerősítés nélkül. - - - Enable double click to copy the username/password entry columns - Dupla kattintás engedélyezése a felhasználónév/jelszó bejegyzésoszlopok másolására - Privacy Adatvédelem @@ -594,6 +648,18 @@ Hide TOTP in the entry preview panel TOTP elrejtése a bejegyzés előnézeti panelen + + Lock databases when switching user + Adatbázis zárolása felhasználóváltáskor + + + Lock Options + Zárolási beállítások + + + Hide notes in the entry preview panel + Jegyzetek elrejtése a bejegyzés-előnézeti panelen + AutoType @@ -641,20 +707,6 @@ Entry does not have attribute for PICKCHARS: %1 A bejegyzés nem rendelkezik PICKCHARS attribútummal: %1 - - Invalid conversion type: %1 - Érvénytelen átalakítási típus: %1 - - - Invalid conversion syntax: %1 - Érvénytelen átalakítási szintaxis: %1 - - - Invalid regular expression syntax %1 -%2 - Érvénytelen reguláriskifejezés-szintaxis %1 -%2 - Invalid placeholder: %1 Érvénytelen helykitöltő: %1 @@ -886,24 +938,25 @@ Válassza ki a helyes adatbázist a hitelesítő adatok mentéséhez. Add to existing entry - + Hozzáadás egy meglévő bejegyzéshez Existing passkey found. Do you want to register a new passkey for: - + Létező jelkulcs található. +Regisztrál ehhez egy új jelkulcsot: Select the existing passkey and press Update to replace it. - + Válassza ki a jelenlegi jelkulcsot, és nyomja meg a Frissítést a cseréjéhez. Authenticate passkey credentials for: - + A jelkulcs hitelesítési adatainak használata ehhez: Do you want to register a passkey for: - + Ehhez szeretne jelkulcsot regisztrálni: @@ -986,16 +1039,17 @@ Valóban törli a bejegyzést? Register a new passkey to this entry: - + Új jelkulcs regisztrálása ehhez a bejegyzéshez: KeePassXC - Update passkey - + KeePassXC – Jelkulcs frissítése Entry already has a passkey. Do you want to overwrite the passkey in %1 - %2? - + A bejegyzéshez már tartozik jelkulcs. +Felülírja az itt található jelkulcsot: %1 – %2? Register @@ -1020,10 +1074,6 @@ Do you want to overwrite the passkey in %1 - %2? General Általános - - Browsers installed as snaps are currently not supported. - A snappal telepített böngészők jelenleg nem támogatottak. - Enable integration for these browsers: Böngészőintegráció engedélyezése a következőkhöz: @@ -1195,18 +1245,6 @@ Do you want to overwrite the passkey in %1 - %2? Custom extension ID Egyéni kiterjesztésazonosító - - Due to Snap sandboxing, you must run a script to enable browser integration.<br />You can obtain this script from %1 - A Snap homokozó miatt egy parancsfájlt kell futtatni a böngészőintegráció engedélyezéséhez.<br />Ezt innen szerezheti be: %1 - - - KeePassXC-Browser is needed for the browser integration to work. <br />Download it for %1 and %2 and %3. %4 - A böngészőintegráció működéséhez a KeePassXC-böngészőre van szükség. <br />Letölthető ezen böngészőkre: %1, %2, %3, 4% - - - Please see special instructions for browser extension use below - Olvassa el a böngészőkiegészítő használatáról szóló különleges utasításokat alább - Executable Files Végrehajtható fájlok @@ -1249,11 +1287,19 @@ Do you want to overwrite the passkey in %1 - %2? Allows using insecure http://localhost with passkeys for testing purposes. - + A nem biztonságos http://localhost engedélyezése a jelkulcsokkal tesztelési célokból. Allow using localhost with passkeys - + Localhost használatának engedélyezése a jelkulcsokkal + + + KeePassXC-Browser is needed for the browser integration to work. <br />Download it for %1 and %2 and %3. + A böngészőintegráció működéséhez a KeePassXC-böngészőre van szükség. <br />Letölthető ezen böngészőkre: %1, %2 és %3. + + + Browsers installed using Snap or Flatpak are not supported with exception to Firefox installed using Snap. + A Snap vagy Flatpak segítségével telepített böngészők nem támogatottak, kivéve a Snap által telepített Firefoxot. @@ -1397,6 +1443,20 @@ Do you want to overwrite the passkey in %1 - %2? Imported from CSV file: %1 CSV-fájlból importálva: %1 + + No Title Selected + Nincs cím kiválasztva + + + No title column was selected, entries will be hard to tell apart. +Are you sure you want to import? + Nincs címoszlop kiválasztva, a bejegyzéseket nehéz lesz megkülönböztetni. +Valóban importálja? + + + Tags + Címkék + CsvParserModel @@ -1460,6 +1520,14 @@ Az adatbázis biztonsági másolata: %2 Recycle Bin Kuka + + Database file read error. + Adatbázisfájl olvasási hiba. + + + No file path was provided. + Nem volt fájlútvonal megadva. + DatabaseOpenDialog @@ -1608,14 +1676,6 @@ Ezen hiba megjelenése megelőzhető az Adatbázis-beállítások → Biztonság <p>In addition to a password, you can use a secret file to enhance the security of your database. This file can be generated in your database's security settings.</p><p>This is <strong>not</strong> your *.kdbx database file!</p> <p>A jelszó mellett egy titkos fájlt is használhat, hogy növelje az adatbázisa biztonságát. Ez a fájl az adatbázis biztonsági beállításaiban állítható elő.</p><p>Ez <strong>nem</strong> a *.kdbx adatbázisfájlja! - - Click to add a key file. - Kattintson egy kulcsfájl hozzáadásához. - - - <a href="#" style="text-decoration: underline">I have a key file</a> - <a href="#" style="text-decoration: underline">Van kulcsfájlom</a> - Use hardware key [Serial: %1] Hardverkulcs használata [Sorozatszám: %1] @@ -1642,7 +1702,7 @@ Are you sure you want to continue with this file?. A kiválasztott fájl adatbázisfájlnak tűnik. Az adatbázis NEM egy kulcsfájl. -Biztos, hogy folytatja ezzel a fájllal? +Valóban folytatja ezzel a fájllal? No hardware keys found. @@ -1652,6 +1712,18 @@ Biztos, hogy folytatja ezzel a fájllal? Refresh Hardware Keys Hardverkulcsok frissítése + + Click to add a key file. + Kattintson egy kulcsfájl hozzáadásához. + + + <a href="#" style="text-decoration: underline">I have a key file</a> + <a href="#" style="text-decoration: underline">Van kulcsfájlom</a> + + + Hardware keys found, but no slots are configured. + A hardverkulcs megtalálva, de a foglalatok nincsenek beállítva. + DatabaseSettingWidgetMetaData @@ -1686,6 +1758,22 @@ Biztos, hogy folytatja ezzel a fájllal? Maintenance Karbantartás + + KeeShare + KeeShare + + + Secret Service Integration + Titkosító szolgáltatás integrációja + + + Remote Sync + Távoli szinkronizálás + + + Database Settings: %1 + Adatbázis-beállítások: %1 + DatabaseSettingsWidgetBrowser @@ -1856,14 +1944,14 @@ Valóban jelszó nélkül folytatja? Weak password Gyenge jelszó - - You must enter a stronger password to protect your database. - Erősebb jelszót kell megadni az adatbázisa védelméhez. - This is a weak password! For better protection of your secrets, you should choose a stronger password. Ez egy gyenge jelszó! A titkai jobb védelme érdekében adjon meg erősebb jelszót. + + The provided password does not meet the minimum quality requirement. + A megadott jelszó nem felel meg a minimális minőségi elvárásoknak. + DatabaseSettingsWidgetEncryption @@ -2165,6 +2253,50 @@ kerülnek az adatbázisból. Autosave delay since last change checkbox Automatikus mentési késleltetés az utolsó módosítás óta jelölőnégyzet + + Public Database Metadata + Nyilvános adatbázis-metaadatok + + + Warning: the following settings are not encrypted. + Figyelmeztetés: a következő beállítások nincsenek titkosítva. + + + Display name: + Megjelenítendő név: + + + Publically visible display name used on the unlock dialog + Nyilvánosan látható megjelenítendő név, amely a feloldási párbeszédablakon használatos + + + Database public display name + Adatbázis nyilvános megjelenítendő neve + + + Display color: + Megjelenítendő szín: + + + Publically visible color used on the unlock dialog + Nyilvánosan látható szín, amely a feloldási párbeszédablakon használatos + + + Database public display color chooser + Adatbázis nyilvános megjelenítendő színének választója + + + Clear + Törlés + + + Display icon: + Megjelenítendő ikon: + + + Select Database Icon + Válasszon adatbázisikont + DatabaseSettingsWidgetKeeShare @@ -2260,6 +2392,141 @@ kerülnek az adatbázisból. Adatbázisleírás mező + + DatabaseSettingsWidgetRemote + + Sync Commands + Szinkronizálási parancs + + + Remove + Eltávolítás + + + Command Settings + Parancsbeállítások + + + Name + Név + + + Save + Mentés + + + Download + Letöltés + + + Command: + Parancs: + + + Download command field + Letöltő parancs mező + + + e.g.: "sftp user@hostname" or "scp user@hostname:DatabaseOnRemote.kdbx {TEMP_DATABASE}" + pl.: „sftp felhasznalo@kiszolgalo” vagy „scp felhasznalo@kiszolgalo:TavoliAdatbazis.kdbx {TEMP_DATABASE}” + + + Input: + Bemenet: + + + Download input field + Letöltő bemeneti mező + + + Upload + Feltöltés + + + Upload command field + Feltöltő parancs mező + + + e.g.: "sftp user@hostname" or "scp {TEMP_DATABASE} user@hostname:DatabaseOnRemote.kdbx" + pl.: „sftp felhasznalo@kiszolgalo” vagy „scp {TEMP_DATABASE}felhasznalo@kiszolgalo:TavoliAdatbazis.kdbx” + + + Upload input field + Feltöltő bemeneti mező + + + Name cannot be empty. + A név nem lehet üres. + + + Test + Tesztelés + + + Download command cannot be empty. + A letöltő parancs nem lehet üres. + + + Download failed with error: %1 + A letöltés hibába ütközött: %1 + + + Download finished, but file %1 could not be found. + A letöltés sikeres, de a fájl nem található: %1. + + + Download successful. + Letöltés sikeres. + + + Save Remote Settings + Távoli beállítások mentése + + + You have unsaved changes. Do you want to save them? + El nem mentett módosítások vannak. Szeretné elmenteni őket? + + + e.g.: +get DatabaseOnRemote.kdbx {TEMP_DATABASE} +exit +--- +{TEMP_DATABASE} is used as placeholder to store the database in a temporary location +The command has to exit. In case of `sftp` as last command `exit` has to be sent + + pl.: +get TavoliAdatbazis.kdbx {TEMP_DATABASE} +exit +--- +{TEMP_DATABASE} helyőrzőként szolgál az adatbázis ideiglenes helyen történő tárolására. +A parancsnak ki kell lépnie, ezért az „sftp” esetében utolsó parancsként az „exit” parancsot el kell küldeni. + + + + e.g.: +put {TEMP_DATABASE} DatabaseOnRemote.kdbx +exit +--- +{TEMP_DATABASE} is used as placeholder to store the database in a temporary location +The command has to exit. In case of `sftp` as last command `exit` has to be sent + + pl.: +put {TEMP_DATABASE} TavoliAdatbazis.kdbx +exit +--- +{TEMP_DATABASE} helyőrzőként szolgál az adatbázis ideiglenes helyen történő tárolására. +A parancsnak ki kell lépnie, ezért az „sftp” esetében utolsó parancsként az „exit” parancsot el kell küldeni. + + + + Timeout: + Időtúllépés: + + + seconds + másodperc + + DatabaseTabWidget @@ -2333,6 +2600,11 @@ Ez határozottan hiba, jelentse a fejlesztőknek. Database tab name modifier %1 [Zárolva] + + %1 [Temporary] + Database tab name modifier + %1 [Ideiglenes] + DatabaseWidget @@ -2456,26 +2728,6 @@ Menti a változásokat? File has changed A fájl módosult - - The database file has changed. Do you want to load the changes? - Az adatbázisfájl módosult. Betölti a módosításokat? - - - Merge Request - Egyesítési kérelem - - - The database file has changed and you have unsaved changes. -Do you want to merge your changes? - Az adatbázisfájl módosult és vannak nem mentett változások. -Egyesíti a módosításokat? - - - Could not open the new database file while attempting to autoreload. -Error: %1 - Nem lehet megnyitni az új adatbázisfájlt egy újranyitási kísérlet közben. -Hiba: %1 - Disable safe saves? Letiltható a biztonságos mentés? @@ -2527,6 +2779,86 @@ Letiltható a biztonságos mentés és úgy megkísérelhető a mentés?Database tab name modifier %1 [Új adatbázis] + + Remote Sync did not contain any download or upload commands. + A távoli szinkronizálás nem tartalmazott le- vagy feltöltési parancsokat. + + + Remote sync '%1' completed successfully! + A távoli szinkronizálás sikeresen befejeződött: %1! + + + Remote sync '%1' failed: %2 + A távoli szinkronizálás (%1) sikertelen: %2 + + + Error while saving database %1: %2 + Hiba az adatbázis (%1) mentése közben: %2 + + + Downloading... + Letöltés… + + + Uploading... + Feltöltés… + + + Syncing... + Szinkronizálás… + + + Remove passkey from entry + Jelkulcs eltávolítása a bejegyzésből + + + Do you want to remove the passkey from this entry? + Valóban eltávolítja a jelkulcsot ebből a bejegyzésből? + + + The database file "%1" was modified externally + A(z) „%1” adatbázisfájl kívülről lett módosítva + + + Do you want to load the changes? + Betölti a módosításokat? + + + Reload database + Adatbázis újratöltése + + + Reloading database… + Adatbázis újratöltése… + + + Reload canceled + Újratöltés megszakítva + + + Reload successful + Újratöltés sikeres + + + Reload pending user action… + Függőben lévő felhasználói művelet újratöltése… + + + The database file "%1" was modified externally.<br>How would you like to proceed?<br><br>Merge all changes<br>Ignore the changes on disk until save<br>Discard unsaved changes + A(z) „%1” adatbázisfájl külsőleg módosítva volt.<br>Hogyan folytatja?<br><br>Összes módosítás egyesítése<br>A módosítások figyelmen kívül hagyása a lemezre mentésig<br>Mentetlen módosítások elvetése + + + The database file "%1" was modified externally.<br>How would you like to proceed?<br><br>Merge all changes then save<br>Overwrite the changes on disk<br>Discard unsaved changes + A(z) „%1” adatbázisfájl külsőleg módosítva volt.<br>Hogyan folytatja?<br><br>Összes módosítás egyesítése, majd mentés<br>A lemezen lévő módosítások felülírása<br>Mentetlen módosítások elvetése + + + Database file overwritten. + Adatbázisfájl felülírva. + + + Database file on disk cannot be unlocked with current credentials.<br>Enter new credentials and/or present hardware key to continue. + A lemezen lévő adatbázisfájl nem oldható fel a jelenlegi hitelesítő adatokkal.<br>A folytatáshoz adjon meg új hitelesítő adatokat, vagy mutasson fel hardverkulcsot. + EditEntryWidget @@ -2578,10 +2910,6 @@ Letiltható a biztonságos mentés és úgy megkísérelhető a mentés?n/a nincs - - (encrypted) - (titkosított) - Select private key Titkos kulcs kijelölése @@ -2684,6 +3012,10 @@ Szeretné kijavítani? %n year(s) %n év%n év + + Failed to decrypt SSH key, ensure password is correct. + Az SSH-kulcs visszafejtése sikertelen, győződjön meg arról, hogy a jelszó helyes. + EditEntryWidgetAdvanced @@ -2855,18 +3187,10 @@ Szeretné kijavítani? Skip Auto-Submit for this entry Automatikus küldés kihagyása ennél a bejegyzésnél - - Only send this setting to the browser for HTTP Auth dialogs. If enabled, normal login forms will not show this entry for selection. - Ezt a beállítást csak a böngésző HTTP hitelesítési párbeszédablakának küldje. Bejelölve a normál bejelentkezési űrlapokon ez a bejegyzés nem fog kiválaszthatóként feltűnni. - Use this entry only with HTTP Basic Auth Bejegyzés alkalmazása csak HTTP Basic hitelesítéssel - - Do not send this setting to the browser for HTTP Auth dialogs. If enabled, HTTP Auth dialogs will not show this entry for selection. - Ne küldje ezt a beállítást a böngésző HTTP hitelesítési párbeszédablakának. Bejelölve a HTTP hitelesítési párbeszédablakokban ez a bejegyzés nem fog kiválaszthatóként feltűnni. - Do not use this entry with HTTP Basic Auth Bejegyzés tiltása HTTP Basic hitelesítéssel @@ -2885,12 +3209,20 @@ Szeretné kijavítani? These settings affect the entry's behaviour with the browser extension. - + Ezek a beállítások hatással vannak a böngészőkiterjesztés viselkedésére. Additional URLs További webcímek + + Only send this entry to the browser for HTTP Auth dialogs. If enabled, normal login forms will not show this entry for selection. + Ezt a bejegyzést csak a böngésző HTTP hitelesítési párbeszédablakának küldje el. Bejelölve a normál bejelentkezési űrlapokon ez a bejegyzés nem fog kiválaszthatóként feltűnni. + + + Do not send this entry to the browser for HTTP Auth dialogs. If enabled, HTTP Auth dialogs will not show this entry for selection. + Ne küldje ezt a bejegyzést a böngésző HTTP hitelesítési párbeszédablakának. Bejelölve a HTTP hitelesítési párbeszédablakokban ez a bejegyzés nem fog kiválaszthatóként feltűnni. + EditEntryWidgetHistory @@ -3113,6 +3445,10 @@ Szeretné kijavítani? seconds másodperc + + Clear agent + Ügynök törlése + EditGroupWidget @@ -3555,6 +3891,24 @@ Ez a kijelölt bővítmény hibás működését eredményezheti. %1 - Clone %1 – Klón + + Passkey + Jelkulcso + + + Invalid conversion type: %1 + Érvénytelen átalakítási típus: %1 + + + Invalid conversion syntax: %1 + Érvénytelen átalakítási szintaxis: %1 + + + Invalid regular expression syntax %1 +%2 + Érvénytelen reguláriskifejezés-szintaxis %1 +%2 + EntryAttachments @@ -3563,6 +3917,21 @@ Ez a kijelölt bővítmény hibás működését eredményezheti. A(z) „%1” fájl nem nyitható meg + + EntryAttachmentsDialog + + Form + Űrlap + + + File name + Fájlnév + + + File contents... + Fájltartalom… + + EntryAttachmentsModel @@ -3600,14 +3969,6 @@ Ez a kijelölt bővítmény hibás működését eredményezheti. Remove Eltávolítás - - Rename selected attachment - Kijelölt melléklet átnevezése - - - Rename - Átnevezés - Open selected attachment Kijelölt melléklet megnyitása @@ -3648,7 +4009,7 @@ Ez a kijelölt bővítmény hibás működését eredményezheti. Are you sure you want to overwrite the existing file "%1" with the attachment? - Valóban felül kívánja írni a meglévő „%1” fájl a melléklettel? + Valóban felülírja a meglévő „%1” fájlt a melléklettel? Confirm overwrite @@ -3692,10 +4053,10 @@ Ez a kijelölt bővítmény hibás működését eredményezheti. Your database may get very large and reduce performance. Are you sure to add this file? - %1 egy nagy fájl (%2 MB). -Az adatbázis így nagyon nagy lesz és rontani fogja a teljesítményt. + A(z) %1 egy nagy fájl (%2 MB). +Az adatbázis így nagyon nagy lesz, és rontani fogja a teljesítményt. -Biztosan hozzáadható ez a fájl? +Valóban hozzáadja ezt a fájlt? Attachment modified @@ -3723,6 +4084,18 @@ Would you like to overwrite the existing attachment? A mellélket már létezik: „%1”. Valóban felülírható a meglévő melléklet? + + New + Új + + + Preview + Előnézet + + + Failed to preview an attachment: Attachment not found + A melléklet előnézete sikertelen: a melléklet nem található + EntryAttributesModel @@ -3921,6 +4294,10 @@ Valóban felülírható a meglévő melléklet? Background Color Háttérszín + + Group Path + Csoportútvonal + EntryPreviewWidget @@ -4315,6 +4692,14 @@ A DuckDuckGo weboldal ikon szolgáltatást az alkalmazás beállításai közöt Url Webcím + + Could not load key file. + A kulcsfájl nem tölthető be. + + + Could not open remote database. Password or key file may be incorrect. + A távoli adatbázis nem nyitható meg. A jelszó vagy a kulcsfájl helytelen lehet. + ImportWizardPageSelect @@ -4418,6 +4803,50 @@ A DuckDuckGo weboldal ikon szolgáltatást az alkalmazás beállításai közöt KeePass1 Database KeePass 1 adatbázis + + Proton Pass (.json) + Proton Pass (.json) + + + Proton Pass JSON Export + Proton Pass JSON-export + + + Temporary Database + Ideiglenes adatbázis + + + Command: + Parancs: + + + e.g.: "sftp user@hostname" or "scp user@hostname:DatabaseOnRemote.kdbx {TEMP_DATABASE}" + pl.: „sftp felhasznalo@kiszolgalo” vagy „scp felhasznalo@kiszolgalo:TavoliAdatbazis.kdbx {TEMP_DATABASE}” + + + Input: + Bemenet: + + + e.g.: +get DatabaseOnRemote.kdbx {TEMP_DATABASE} +exit +--- +{TEMP_DATABASE} is used as placeholder to store the database in a temporary location +The command has to exit. In case of `sftp` as last commend `exit` has to be sent + + például: +get TavoliAdatbazis.kdbx {TEMP_DATABASE} +exit +--- +A {TEMP_DATABASE} helyőrzőként szolgál az adatbázis ideiglenes helyen történő tárolására. +A parancsnak ki kell lépnie, ezért az „sftp” esetén utolsó parancsként el kell küldeni az „exit” parancsot. + + + + Remote Database (.kdbx) + Távoli adatbázis (.kdbx) + KMessageWidget @@ -5557,12 +5986,6 @@ Ez a verzió nem felhasználóknak készült. Expect some bugs and minor issues, this version is meant for testing purposes. MEGJEGYZÉS: Ez egy előzetes kiadású KeePassXC verzió. Néhány hiba és kisebb nehézségek várhatóak, ezért ez a verzió tesztelési célra való. - - - WARNING: Your Qt version may cause KeePassXC to crash with an On-Screen Keyboard. -We recommend you use the AppImage available on our downloads page. - FIGYELMEZTETÉS: A Qt verziója miatt a KeePassXC összeomolhat egy képernyő-billentyűzettel. -Javasoljuk az AppImage alkalmazását, amely elérhető a letöltések oldalon. No Tags @@ -5636,6 +6059,10 @@ Javasoljuk az AppImage alkalmazását, amely elérhető a letöltések oldalon.< Import Passkey Jelkulcs importálása + + Remote S&ync… + Távoli &szinkronizálás… + Quit Application Kilépés az alkalmazásból @@ -5740,6 +6167,10 @@ Javasoljuk az AppImage alkalmazását, amely elérhető a letöltések oldalon.< Show Password Generator Jelszó-előállító megjelenítése + + Remove Passkey From Entry + Jelkulcs eltávolítása a bejegyzésből + Perform Auto-Type: {USERNAME} Automatikus beírás végrehajtása: {USERNAME} @@ -5884,6 +6315,34 @@ Javasoljuk az AppImage alkalmazását, amely elérhető a letöltések oldalon.< Toggle Allow Screen Capture Képernyőrögzítés engedélyezése be/ki + + Show Group Panel + Csoport panel megjelenítése + + + Toggle Show Group Panel + Csoport panel megjelenítése be/ki + + + Setup Remote Sync… + Távoli szinkronizálás beállításai + + + Password Generator + Jelszógenerátor + + + E&xpire Entry… + Bejegyzés &elévültté tétele… + + + Clear SSH Agent + SSH-ügynök törlése + + + Clear all identities in ssh-agent + Az ssh-agentben található összes személyazonosság törlése + ManageDatabase @@ -6034,6 +6493,25 @@ Javasoljuk az AppImage alkalmazását, amely elérhető a letöltések oldalon.< Töltse ki a megjelenítendő nevet és a nem kötelező leírást az új adatbázishoz: + + NewEntryAttachmentsDialog + + Attachment name cannot be empty + A melléklet neve nem lehet üres + + + Attachment with the same name already exists + Már létezik ugyanilyen nevű melléklet + + + Save attachment + Melléklet mentése + + + New entry attachment + Új bejegyzésmelléklet + + NixUtils @@ -6221,6 +6699,10 @@ Javasoljuk az AppImage alkalmazását, amely elérhető a letöltések oldalon.< Unexpected EOF when writing private key Nem várt EOF a titkos kulcs írásakor + + (encrypted) + (titkosított) + OpenSSHKeyGenDialog @@ -6269,7 +6751,7 @@ Javasoljuk az AppImage alkalmazását, amely elérhető a letöltések oldalon.< Export the following passkey entries. - + A következő jelkulcsot tartalmazó bejegyzések exportálása. @@ -6343,15 +6825,15 @@ Felülírja? Import the following passkey: - + A következő jelkulcs importálása: Import the following passkey to this entry: - + A következő jelkulcs importálása ebbe a bejegyzésbe: Default passkeys group (Imported Passkeys) - + Jelkulcsok alapértelmezett csoportja (importált jelkulcsok) @@ -6374,25 +6856,27 @@ Felülírja? Open passkey file - + Jelkulcsfájl megnyitása Cannot import passkey - + A jelkulcs nem importálható Cannot import passkey file "%1". Data is missing. - + A(z) „%1” jelkulcsfájl nem importálható. Az adatok hiányoznak. Cannot import passkey file "%1". The following data is missing: %2 - + A(z) „%1” jelkulcsfájl nem importálható. +A következő adatok hiányoznak: +%2 Cannot import passkey file "%1". Private key is missing or malformed. - + A(z) „%1” jelkulcsfájl nem importálható. A titkos kulcs hiányzik vagy hibás. @@ -6573,10 +7057,6 @@ The following data is missing: Also choose from: Tartalmazhat ezekből is: - - Excluded characters: "0", "1", "l", "I", "O", "|", "﹒" - Kihagyott karakterek: „0”, „1”, „l”, „I”, „O”, „|”, „﹒” - Exclude look-alike characters Hasonlóan kinéző karakterek kizárása @@ -6601,10 +7081,6 @@ The following data is missing: Word Count: Szavak száma: - - Character Count: - Karakterszám: - Word Case: Minden Szó Nagybetűs @@ -6617,10 +7093,6 @@ The following data is missing: Add custom wordlist Egyéni szólista hozzáadása - - character - karakter - Close Bezárás @@ -6727,6 +7199,22 @@ Valóban felülírja? Special Characters Speciális karakterek + + passwordLength + jelszóhossz + + + Characters: %1 + Karakterszám: %1 + + + MIXED case + VEGYES eset + + + Excluded characters: "0", "1", "l", "I", "O", "|", "﹒", "B", "8", "G", "6" + Kihagyott karakterek: „0”, „1”, „l”, „I”, „O”, „|”, „﹒”, „B”, „8”, „G”, „6” + PasswordWidget @@ -6794,6 +7282,21 @@ Valóban felülírja? Nyomja meg a &Tab billentyűt a karakterek között + + PreviewEntryAttachmentsDialog + + Preview entry attachment + Bejegyzésmelléklet előnézete + + + No preview available + Nem érhető el előnézet + + + Image format not supported + A képformátum nem támogatott + + QMessageBox @@ -7472,10 +7975,6 @@ Valóban felülírja? Invalid word count %1 Érvénytelen a szavak száma: %1 - - The word list is too small (< 1000 items) - A szavak listája túl rövid (< 1000 elem) - Title for the entry. Bejegyzés címe. @@ -7620,10 +8119,6 @@ Valóban felülírja? Exit interactive mode. Kilépés az interaktív módból. - - Format to use when exporting. Available choices are 'xml' or 'csv'. Defaults to 'xml'. - Exportálási formátum. Lehetőségek: „xml” vagy „csv”. Az alapértelmezett az „xml”. - Exports the content of a database to standard output in the specified format. Szabványos kimenetre exportálja az adatbázis tartalmát a meghatározott formátumban. @@ -8212,18 +8707,6 @@ Kernel: %3 %4 file empty a fájl üres - - malformed string - rosszul formázott karakterlánc - - - missing closing quote - hiányzó lezáró idézőjel - - - %1: (row, col) %2,%3 - %1: (sor, oszlop) %2,%3 - AES 256-bit 256 bites AES @@ -8467,7 +8950,8 @@ Kernel: %3 %4 Set the key file for the database. This option is deprecated, use --set-key-file instead. - + A kulcsfájl beállítása az adatbázishoz. +Ez a kapcsoló elavult, használja helyette a --set-key-file kapcsolót. Databases have been locked. @@ -8668,13 +9152,89 @@ This option is deprecated, use --set-key-file instead. Gyorsbillentyűk - Unsupported KDF type, cannot decrypt json file + Unknown passkeys error + Ismeretlen, jelkulcsokkal kapcsolatos hiba + + + Invalid KDF iterations, cannot decrypt json file + Érvénytelen KDF iterációk, a JSON-fájl nem fejthető vissza + + + Unsupported format, ensure your Bitwarden export is password-protected + Nem támogatott formátum, győződjön meg róla, hogy a Bitwarden exportja jelszóval védett. + + + Only PBKDF and Argon2 are supported, cannot decrypt json file + Csak a PBKDF és az Argon2 támogatott, a JSON-fájl nem fejthető vissza + + + Reset Shortcuts + Gyorsbillentyűk visszaállítása + + + Double click an action to change its shortcut + Kattintson duplán egy műveletre a gyorsbillentyűje módosításához + + + Filter... + Szűrő… + + + Shortcut Conflict + Gyorsbillentyű-ütközés + + + Shortcut %1 conflicts with '%2'. Overwrite shortcut? + A(z) %1 gyorsbillentyű ütközik ezzel: „%2”. Felülírja? + + + Cannot generate valid passphrases because the wordlist is too short + Nem lehet érvényes jelszavakat generálni, mert a szólista túl rövid + + + Encrypted files are not supported. + A titkosított fájlok nem támogatottak + + + Proton Pass Import + Proton Pass importálás + + + Delete plugin data? + Törölhetők a bővítmény adatai? + + + Delete plugin data from Entry(s)? + Törölhetők a bővítmény adatai a bejegyzésekből?Törölhetők a bővítmény adatai a bejegyzésekből? + + + Passkey + Jelkulcso + + + Format to use when exporting. Available choices are 'xml', 'csv' or 'html'. Defaults to 'xml'. + Exportálási formátum. Lehetőségek: „xml”, „csv” vagy „html”. Az alapértelmezett az „xml”. + + + start minimized to the system tray + indítás a rendszertálcára minimalizálva + + + malformed string, possible unescaped delimiter - Unknown passkeys error + missing closing delimiter + + %1, row: %2, column: %3 + + + + Tags + Címkék + QtIOCompressor @@ -8710,6 +9270,37 @@ This option is deprecated, use --set-key-file instead. Belső zlib hiba: + + RemoteHandler + + Command `%1` did not finish in time. Process was killed. + A parancs nem fejeződött be időben: „%1”. A folyamat kilőve. + + + Failed to upload merged database. Command `%1` did not finish in time. Process was killed. + Nem sikerült feltölteni az egyesített adatbázist. A parancs nem fejeződött be időben: „%1”. A folyamat kilőve. + + + Invalid download parameters provided. + Érvénytelen letöltési paraméterek lettek megadva. + + + Command `%1` failed to download database. + A parancs nem tudta letölteni az adatbázist: „%1”. + + + Invalid database pointer or upload parameters provided. + Érvénytelen adatbázismutató vagy feltöltési paraméterek lettek megadva. + + + Command `%1` exited with status code: %2 + A parancs (%1) ezzel az állapotkóddal lépett ki: %2 + + + Failed to upload merged database. Command `%1` exited with status code: %2 + Az egyesített adatbázis feltöltése sikertelen. A parancs (%1) ezzel az állapotkóddal lépett ki: %2 + + ReportsWidgetBrowserStatistics @@ -8776,6 +9367,10 @@ This option is deprecated, use --set-key-file instead. Exclude from reports Kizárás a jelentésekből + + Expire Entry(s)… + Bejegyzés elévültté tétele…Bejegyzések elévültté tétele… + Only show entries that have a URL Csak a webcímmel rendelkező bejegyzések megjelenítése @@ -8792,36 +9387,33 @@ This option is deprecated, use --set-key-file instead. (Expired) (Lejárt) + + Delete plugin data from Entry(s)… + Bővítmény adatainak törlése a bejegyzésekből…Bővítmény adatainak törlése a bejegyzésekből… + ReportsWidgetHealthcheck - Hover over reason to show additional details. Double-click entries to edit. - Vigye az egérmutatót az ok felé a további részletek megjelenítéséhez. Kattintson duplán a bejegyzésekre a szerkesztéshez. + Show expired entries + Lejárt bejegyzések megjelenítése - Bad - Password quality - Rossz + (Expired) + (Lejárt) + + + Hover over reason to show additional details. Double-click entries to edit. + Vigye az egérmutatót az ok felé a további részletek megjelenítéséhez. Kattintson duplán a bejegyzésekre a szerkesztéshez. Bad — password must be changed Rossz – a jelszót meg kell változtatni - - Poor - Password quality - Silány - Poor — password should be changed Silány – a jelszót meg kellene változtatni - - Weak - Password quality - Gyenge - Weak — consider changing the password Gyenge - Megfontolandó a jelszó változtatása @@ -8870,18 +9462,14 @@ This option is deprecated, use --set-key-file instead. Exclude from reports Kizárás a jelentésekből - - Show expired entries - Lejárt bejegyzések megjelenítése + + Expire Entry(s)… + Bejegyzés elévültté tétele…Bejegyzések elévültté tétele… Show entries that have been excluded from reports A jelentésekből kizárt bejegyzések megjelenítése - - (Expired) - (Lejárt) - ReportsWidgetHibp @@ -8977,6 +9565,10 @@ This option is deprecated, use --set-key-file instead. Exclude from reports Kizárás a jelentésekből + + Expire Entry(s)… + Bejegyzés elévültté tétele…Bejegyzések elévültté tétele… + ReportsWidgetPasskeys @@ -9034,15 +9626,15 @@ This option is deprecated, use --set-key-file instead. The passkey file will be vulnerable to theft and unauthorized use, if left unsecured. Are you sure you want to continue? - A jelkulcsfájl védtelenül hagyva lopásnak és illetéktelen használatnak van kitéve. Biztos, hogy folytatni akarja? + A jelkulcsfájl védtelenül hagyva lopásnak és illetéktelen használatnak van kitéve. Valóban folytatja? Please wait, list of entries with passkeys is being updated… - + Kis türelmet, a jelkulcsot tartalmazó elemek listája frissül… No entries with passkeys. - + Nincsenek jelkulcsot tartalmazó elemek. @@ -9218,6 +9810,14 @@ This option is deprecated, use --set-key-file instead. No agent running, cannot list identities. Nincs működő ügynök, identitások nem listázhatóak. + + Failed to remove all SSH identities from agent. + Az ügynök összes személyazonosságának törlése sikertelen + + + All SSH identities removed from agent. + Az ügynök összes személyazonossága törölve. + SearchHelpWidget @@ -9392,11 +9992,12 @@ This option is deprecated, use --set-key-file instead. <html><head/><body><p>This setting does not override disabling recycle bin prompts </p></body></html> - + <html><head/><body><p>Ez a beállítás nem bírálja felül a kukába helyezési kérdések letiltását </p></body></html> <html><head/><body><p>This improves compatibility with certain applications which search for password without unlocking the database first.</p><p>But enabling this may also crash the client if the database can not be unlocked within a certain timeout. (Usually 25s, but may be a different value set in applications.) </p></body></html> - + <html><head/><body><p>Ez növeli a kompatibilitást bizonyos alkalmazásokkal, melyek az adatbázis előzetes feloldása nélkül keresnek jelszót.</p><p>De az engedélyezése miatt összeomolhat a kliens, ha az adatbázis nem kerül feloldásra egy bizonyos időtúllépésen belül. (Általában 25 mp, de más érték lehet megadva az alkalmazásokban.)</p></body></html> + @@ -9503,29 +10104,6 @@ This option is deprecated, use --set-key-file instead. Exportálás: %1 - - ShortcutSettingsWidget - - Double click an action to change its shortcut - Kattintson duplán egy műveletre a gyorsbillentyűje módosításához - - - Shortcut Conflict - Gyorsbillentyű-ütközés - - - Filter... - Szűrő… - - - Shortcut %1 conflicts with '%2'. Overwrite shortcut? - A(z) %1 gyorsbillentyű ütközik ezzel: „%2”. Felülírja? - - - Reset Shortcuts - Gyorsbillentyűk visszaállítása - - TagModel @@ -9814,14 +10392,18 @@ Példa: JBSWY3DPEHPK3PXP No hardware keys detected Nincsenek felismert hardverkulcsok. - - <p>If you own a <a href="https://www.yubico.com/">YubiKey</a> or <a href="https://onlykey.io">OnlyKey</a>, you can use it for additional security.</p><p>The key requires one of its slots to be programmed as <a href="https://docs.yubico.com/yesdk/users-manual/application-otp/challenge-response.html">HMAC-SHA1 Challenge-Response</a>.</p> - <p>Ha van <a href="https://www.yubico.com/">YubiKey</a> vagy <a href="https://onlykey.io">OnlyKey</a> eszköze, akkor használhatja a további biztonság érdekében.</p><p>Kulcs szükséges, hogy az egyik foglalata <a href="https://docs.yubico.com/yesdk/users-manual/application-otp/challenge-response.html">HMAC-SHA1 kihívás-válaszként</a> legyen beállítva.</p> - Refresh hardware keys Hardverkulcsok frissítése + + <p>If you own a <a href="https://www.yubico.com/">YubiKey</a> or <a href="https://onlykey.io">OnlyKey</a>, you can use it for additional security.</p><p>The key requires one of its slots to be programmed with <a href="https://keepassxc.org/docs/#faq-yubikey-howto">Challenge-Response</a>.</p> + <p>Ha van <a href="https://www.yubico.com/">YubiKey</a> vagy <a href="https://onlykey.io">OnlyKey</a> eszköze, akkor használhatja a további biztonság érdekében.</p><p>A kulcs megköveteli, hogy az egyik foglalata <a href="https://keepassxc.org/docs/#faq-yubikey-howto">kihívás-válaszként</a> legyen beprogramozva.</p> + + + Hardware keys found, but no slots are configured + A hardverkulcs megtalálva, de a foglalatok nincsenek beállítva + YubiKeyInterfacePCSC diff --git a/share/translations/keepassxc_id.ts b/share/translations/keepassxc_id.ts index 65517114b..585cb1a73 100644 --- a/share/translations/keepassxc_id.ts +++ b/share/translations/keepassxc_id.ts @@ -217,18 +217,50 @@ You must restart the application to set the new language. Would you like to restart now? Anda harus memulai ulang aplikasi untuk menerapkan bahasa. Apakah Anda ingin memulai ulang sekarang? - - Reset Settings? - Atur Ulang Pengaturan? - - - Are you sure you want to reset all general and security settings to default? - Apakah Anda yakin ingin mengatur ulang pengaturan umum dan keamanan ke nilai bawaan? - Select backup storage directory Pilih direktori penyimpanan cadangan + + Confirm Reset + Konfirmasi Reset + + + Are you sure you want to reset all settings to default? + Apakah Anda yakin ingin mereset semua pengaturan ke kondisi bawaan? + + + Import KeePassXC Settings + Impor Pengaturan KeePassXC + + + Failed to import settings from %1, not a valid settings file. + Gagal mengimpor pengaturan dari %1, bukan berkas pengaturan yang valid. + + + Export KeePassXC Settings + Ekspor Pengaturan KeePassXC + + + Small + + + + Normal + + + + Medium + + + + Large + + + + Custom + + ApplicationSettingsWidgetGeneral @@ -280,25 +312,6 @@ Include beta releases when checking for updates Termasuk rilis beta saat memeriksa pembaruan - - On database unlock, show entries that - Pada pembukaan kunci basis data, tampilkan entri yang - - - have expired - On database unlock, show entries that... - telah kedaluwarsa - - - days - On database unlock, show entries that will expire within %1 days - hari - - - will expire within - On database unlock, show entries that... - akan kedaluwarsa dalam masa - File Management Manajemen Berkas @@ -323,22 +336,10 @@ Backup database file before saving Cadangkan basis data sebelum disimpan - - Backup destination - Destinasi cadangan - - - Specifies the database backup file location. Occurrences of "{DB_FILENAME}" are replaced with the filename of the saved database without extension. {TIME:<format>} is replaced with the backup time, see https://doc.qt.io/qt-5/qdatetime.html#toString. <format> defaults to format string "dd_MM_yyyy_hh-mm-ss". - Specifies the database backup file location. Occurrences of "{DB_FILENAME}" are replaced with the filename of the saved database without extension. {TIME:<format>} is replaced with the backup time, see https://doc.qt.io/qt-5/qdatetime.html#toString. <format> defaults to format string "dd_MM_yyyy_hh-mm-ss". - {DB_FILENAME}.old.kdbx {DB_FILENAME}.old.kdbx - - Choose... - Pilih... - Use alternative saving method (may solve problems with Dropbox, Google Drive, GVFS, etc.) Gunakan metode penyimpanan alternatif (mungkin akan mengatasi masalah dengan Dropbox, Google Drive, GVFS, dll.) @@ -505,6 +506,71 @@ Remember last typed entry for: Ingat entri yang terakhir diketikkan untuk: + + On database unlock, show entries that will expire within + Pada basis data tidak terkunci, tampilkan entri yang akan kedaluwarsa selama + + + On database unlock, show entries that will expire within + Pada basis data tidak terkunci, tampilkan entri yang akan kedaluwarsa selama + + + days + number of days warning for password expiration + hari + + + Destination format: + Format yang diinginkan: + + + <html><head/><body><p><span style=" font-weight:600;">{DB_FILENAME}</span> is replaced with the filename of the saved database without extension</p><p><span style=" font-weight:600;">{TIME:&lt;format&gt;}</span> is replaced with the specified time format (default: dd_MM_yyyy_hh-mm-ss)</p><p>See the User Guide for more details</p></body></html> + <html><head/><body><p><span style=" font-weight:600;">{DB_FILENAME}</span> telah diganti dengan nama file dari database yang disimpan tanpa ekstensi </p><p><span style=" font-weight:600;">{TIME:&lt;format&gt;}</span> telah diganti dengan format waktu yang ditentukan (bawaan: dd_MM_yyyy_hh-mm-ss)</p><p> Lihat Panduan Pengguna untuk detail lebih lanjut </p></body></html> + + + Choose folder... + Pilih folder... + + + Show confirmation before moving entries to recycle bin + Tampilkan konfirmasi sebelum memindahkan entri ke tempat sampah + + + Copy data on double clicking field in entry view + Menyalin data dengan mengklik dua kali kolom di tampilan entri + + + Show toolbar + Tampilkan bilah alat + + + Show the menu bar by pressing the Alt key + Menampilkan bilah menu dengan menekan tombol Alt + + + Show menubar + Menampilkan bilah menu + + + Import settings… + Impor pengaturan... + + + Export settings… + Ekspor pengaturan... + + + Open browser on double clicking URL field in entry view + Buka peramban dengan mengklik dua kali kolom URL di tampilan entri + + + Font size: + + + + Font size selection + + ApplicationSettingsWidgetSecurity @@ -570,18 +636,6 @@ Hide passwords in the entry preview panel Sembunyikan sandi di panel pratinjau entri - - Hide entry notes by default - Sembunyikan catatan secara bawaan - - - Move entries to recycle bin without confirmation - Hapus entri ke keranjang sampah tanpa konfirmasi - - - Enable double click to copy the username/password entry columns - Klik dua kali untuk menyalin kolom entri nama pengguna/sandi - Privacy Privasi @@ -594,6 +648,18 @@ Hide TOTP in the entry preview panel Sembunyikan TOTP di panel pratinjau entri + + Lock databases when switching user + Mengunci basis data saat berpindah pengguna + + + Lock Options + Opsi Penguncian + + + Hide notes in the entry preview panel + Sembunyikan catatan di panel pratinjau entri + AutoType @@ -641,20 +707,6 @@ Entry does not have attribute for PICKCHARS: %1 Entri tidak memiliki atribut untuk PICKCHARS: %1 - - Invalid conversion type: %1 - Tipe konversi tidak valid: %1 - - - Invalid conversion syntax: %1 - Sintaks konversi tidak valid: %1 - - - Invalid regular expression syntax %1 -%2 - Sintaks ekspresi reguler %1 tidak valid -%2 - Invalid placeholder: %1 Invalid placeholder: %1 @@ -714,7 +766,7 @@ Trying to send invalid keyboard symbol. - + Mencoba mengirim simbol keyboard yang tidak valid. @@ -874,36 +926,37 @@ Silakan pilih basis data yang digunakan untuk menyimpan kredensial. Relying Party: %1 - + Pihak yang Mengandalkan: %1 Username: %1 - + Nama pengguna: %1 KeePassXC - Passkey credentials - + KeePassXC - Kunci Akses Digital Add to existing entry - + Tambahkan ke entri yang telah ada Existing passkey found. Do you want to register a new passkey for: - + Kunci akses yang ada ditemukan. +Anda ingin mendaftarkan kunci akses baru: Select the existing passkey and press Update to replace it. - + Pilih kunci akses yang ada, lalu tekan Perbarui untuk menggantinya. Authenticate passkey credentials for: - + Mengautentikasi kredensial kunci akses: Do you want to register a passkey for: - + Apakah Anda ingin mendaftarkan kunci akses: @@ -952,11 +1005,11 @@ Do you want to delete the entry? %1 (Passkey) - + %1 (Kunci akses) KeePassXC - Create a new group - + KeePassXC - Buat grup baru Disable @@ -968,36 +1021,37 @@ Do you want to delete the entry? KeePassXC - Update Entry - + KeePassXC - Perbarui Entri KeePassXC - Delete entry - + KeePassXC - Hapus Entry KeePassXC - New key association request - + KeePassXC - Permintaan asosiasi kunci baru Passkey - + Kunci akses KeePassXC - Passkey credentials - + KeePassXC - Kunci Akses Digital Register a new passkey to this entry: - + Daftarkan kunci akses baru ke entri ini: KeePassXC - Update passkey - + KeePassXC - Perbarui kunci akses Entry already has a passkey. Do you want to overwrite the passkey in %1 - %2? - + Entri sudah memiliki kunci akses. +Apakah Anda ingin menimpa kunci akses di %1 - %2? Register @@ -1022,10 +1076,6 @@ Do you want to overwrite the passkey in %1 - %2? General Umum - - Browsers installed as snaps are currently not supported. - Peramban yang dipasang sebagai snap saat ini tidak didukung. - Enable integration for these browsers: Aktifkan integrasi untuk peramban ini: @@ -1197,18 +1247,6 @@ Do you want to overwrite the passkey in %1 - %2? Custom extension ID ID ekstensi khusus - - Due to Snap sandboxing, you must run a script to enable browser integration.<br />You can obtain this script from %1 - Karena adanya sandbox Snap, Anda harus menjalankan skrip untuk mengaktifkan integrasi peramban.<br />Anda bisa mendapatkan skrip ini dari %1 - - - KeePassXC-Browser is needed for the browser integration to work. <br />Download it for %1 and %2 and %3. %4 - Membutuhkan KeePassXC-Browser agar integrasi peramban bisa bekerja. <br />Silakan unduh untuk %1 dan %2 dan %3. %4 - - - Please see special instructions for browser extension use below - Lihat instruksi untuk penggunaan browser extension - Executable Files Berkas Executable @@ -1227,11 +1265,11 @@ Do you want to overwrite the passkey in %1 - %2? Allow keepassxc-proxy to list all entries with their title, URL and UUID in connected databases. - + Izinkan keepassxc-proksi untuk menampilkan semua entri dengan judul, URL, dan UUID-nya di basis data yang terhubung. Allow limited access to all entries in connected databases (ignores site access restrictions) - + Izinkan akses terbatas ke semua entri di basis data yang terhubung (abaikan pembatasan akses situs) <b>Warning:</b> Only adjust these settings if necessary. @@ -1251,10 +1289,18 @@ Do you want to overwrite the passkey in %1 - %2? Allows using insecure http://localhost with passkeys for testing purposes. - + Mengizinkan penggunaan http://localhost yang tidak aman dengan kunci akses untuk tujuan pengujian. Allow using localhost with passkeys + Mengizinkan penggunaan host lokal dengan kunci akses + + + KeePassXC-Browser is needed for the browser integration to work. <br />Download it for %1 and %2 and %3. + KeePassXC-Browser diperlukan agar integrasi peramban dapat bekerja. <br />Unduh untuk %1 dan %2 dan %3. + + + Browsers installed using Snap or Flatpak are not supported with exception to Firefox installed using Snap. @@ -1393,11 +1439,25 @@ Do you want to overwrite the passkey in %1 - %2? Failed to parse CSV file: %1 - + Gagal untuk mengurai file CSV: %1 Imported from CSV file: %1 - + Diimpor dari file CSV: %1 + + + No Title Selected + Tidak ada Judul yang Dipilih + + + No title column was selected, entries will be hard to tell apart. +Are you sure you want to import? + Tidak ada kolom judul yang dipilih, entri akan sulit dibedakan. +Apakah Anda yakin ingin mengimpor? + + + Tags + Tag @@ -1462,6 +1522,14 @@ Lokasi cadangan basis data ada di %2 Recycle Bin Keranjang Sampah + + Database file read error. + + + + No file path was provided. + + DatabaseOpenDialog @@ -1599,54 +1667,62 @@ Untuk mencegah munculnya kesalahan ini, Anda harus ke "Pengaturan Basis Dat Failed to authenticate with Quick Unlock: %1 - + Gagal mengautentikasi dengan Buka Kunci Cepat: %1 Select Key File: - + Pilih Berkas Kunci: <p>In addition to a password, you can use a secret file to enhance the security of your database. This file can be generated in your database's security settings.</p><p>This is <strong>not</strong> your *.kdbx database file!</p> - - - - Click to add a key file. - - - - <a href="#" style="text-decoration: underline">I have a key file</a> - + <p> Selain kata sandi, Anda dapat menggunakan berkas rahasia untuk meningkatkan keamanan basis data Anda. Berkas ini dapat dibuat dalam pengaturan keamanan basis data Anda.</p><p>Ini <strong> bukanlah </strong> berkas basis data *.kdbx anda! </p> Use hardware key [Serial: %1] - + Gunakan kunci perangkat keras [Serial: %1] Use hardware key - + Gunakan kunci perangkat keras Your database file is NOT a key file! If you don't have a key file or don't know what that is, you don't have to select one. - + Berkas basis data Anda BUKAN berkas kunci! +Jika Anda tidak memiliki berkas kunci atau tidak paham apa itu berkas kunci, Anda tidak perlu memilihnya. KeePassXC database file selected - + Berkas basis data KeePassXC dipilih The file you selected looks like a database file. A database file is NOT a key file! Are you sure you want to continue with this file?. - + Berkas yang Anda pilih terlihat seperti berkas basis data. +Berkas basis data BUKAN berkas kunci! + +Apakah Anda yakin ingin melanjutkan dengan berkas ini? No hardware keys found. - + Tidak ditemukan kunci perangkat keras. Refresh Hardware Keys + Segarkan kunci perangkat keras. + + + Click to add a key file. + Klik untuk tambahkan berkas kunci. + + + <a href="#" style="text-decoration: underline">I have a key file</a> + <a href="#" style="text-decoration: underline">Aku punya berkas kunci</a> + + + Hardware keys found, but no slots are configured. @@ -1683,6 +1759,22 @@ Are you sure you want to continue with this file?. Maintenance Pemeliharaan + + KeeShare + KeeShare + + + Secret Service Integration + Integrasi Layanan Rahasia + + + Remote Sync + Sinkronisasi Jarak Jauh + + + Database Settings: %1 + Pengaturan basis data: %1 + DatabaseSettingsWidgetBrowser @@ -1796,19 +1888,19 @@ Ini hanya diperlukan jika basis data Anda adalah salinan dari basis data yang la No keys found - + Kunci tidak ditemukan Removed keys from database - + Kunci terhapus dari basis data Removed permissions - + Izin terhapus No entry with permissions found! - + Tidak ditemukan entri yang memiliki izin! @@ -1854,12 +1946,12 @@ Apakah Anda tetap ingin melanjutkan tanpa mengatur sandi? Kata sandi lemah - You must enter a stronger password to protect your database. - + This is a weak password! For better protection of your secrets, you should choose a stronger password. + Ini adalah kata sandi yang lemah! Untuk perlindungan yang lebih baik terhadap rahasia Anda, Anda harus memilih kata sandi yang lebih kuat. - This is a weak password! For better protection of your secrets, you should choose a stronger password. - + The provided password does not meet the minimum quality requirement. + Kata sandi yang dimasukkan tidak memenuhi persyaratan standar minimum. @@ -1998,15 +2090,15 @@ If you keep this number, your database will not be protected from brute force at thread(s) Threads for parallel execution (KDF settings) - + Untaian(s) Encryption Settings: - + Pengaturan Enkripsi: Basic - + Dasar Advanced @@ -2144,15 +2236,15 @@ dipindahkan dari basis data. Autosave delay since last change - + Jeda penyimpanan otomatis sejak perubahan terakhir Autosave delay - + Jeda penyimpanan otomatis Autosave delay since last change in minutes - + Jeda penyimpanan otomatis sejak perubahan terakhir dalam menit min @@ -2160,7 +2252,51 @@ dipindahkan dari basis data. Autosave delay since last change checkbox - + Kotak centang jeda penyimpanan otomatis sejak perubahan terakhir + + + Public Database Metadata + Metadata Basis data Publik + + + Warning: the following settings are not encrypted. + Peringatan: pengaturan berikut ini tidak terenkripsi. + + + Display name: + Nama tampilan: + + + Publically visible display name used on the unlock dialog + Nama tampilan yang dapat dilihat oleh publik yang digunakan pada obrolan terbuka + + + Database public display name + Nama tampilan publik basis data + + + Display color: + Warna tampilan: + + + Publically visible color used on the unlock dialog + Warna yang terlihat publik yang digunakan pada obrolan terbuka + + + Database public display color chooser + Pemilih warna tampilan publik basis data + + + Clear + Bersihkan + + + Display icon: + Ikon tampilan: + + + Select Database Icon + Pilih ikon Basis data @@ -2235,7 +2371,7 @@ dipindahkan dari basis data. Purged %n icon(s) from the database. - + Menghapus ikon(s) %n dari basis data. @@ -2257,6 +2393,141 @@ dipindahkan dari basis data. Ruas deskripsi basis data + + DatabaseSettingsWidgetRemote + + Sync Commands + Perintah Sinkronikasi + + + Remove + Buang + + + Command Settings + Pengaturan Perintah + + + Name + Nama + + + Save + Simpan + + + Download + Unduh + + + Command: + Perintah: + + + Download command field + Kolom perintah unduhan + + + e.g.: "sftp user@hostname" or "scp user@hostname:DatabaseOnRemote.kdbx {TEMP_DATABASE}" + misal: "sftp user@hostname" atau "scp user@hostname:DatabaseOnRemote.kdbx {TEMP_DATABASE}" + + + Input: + Input: + + + Download input field + Kolom input unduhan + + + Upload + Unggah + + + Upload command field + Kolom perintah unggahan + + + e.g.: "sftp user@hostname" or "scp {TEMP_DATABASE} user@hostname:DatabaseOnRemote.kdbx" + misal: "sftp user@hostname" atau "scp {TEMP_DATABASE} user@hostname:DatabaseOnRemote.kdbx" + + + Upload input field + Kolom input unggahan + + + Name cannot be empty. + Nama tidak boleh kosong + + + Test + Tes + + + Download command cannot be empty. + Perintah unduhan tidak boleh kosong. + + + Download failed with error: %1 + Pengunduhan gagal dengan galat: %1 + + + Download finished, but file %1 could not be found. + Pengunduhan selesai, tetapi berkas %1 tidak dapat ditemukan. + + + Download successful. + Pengunduhan berhasil. + + + Save Remote Settings + Simpan Pengaturan Jarak Jauh + + + You have unsaved changes. Do you want to save them? + Anda memiliki perubahan yang belum disimpan. Apakah Anda ingin menyimpannya? + + + e.g.: +get DatabaseOnRemote.kdbx {TEMP_DATABASE} +exit +--- +{TEMP_DATABASE} is used as placeholder to store the database in a temporary location +The command has to exit. In case of `sftp` as last command `exit` has to be sent + + misal: +get DatabaseOnRemote.kdbx {TEMP_DATABASE} +keluar +--- +{TEMP_DATABASE} digunakan sebagai penampung untuk menyimpan basis data di lokasi sementara +Perintah tersebut harus keluar. Dalam kasus `sftp` sebagai perintah terakhir, `keluar` harus dilakukan + + + + e.g.: +put {TEMP_DATABASE} DatabaseOnRemote.kdbx +exit +--- +{TEMP_DATABASE} is used as placeholder to store the database in a temporary location +The command has to exit. In case of `sftp` as last command `exit` has to be sent + + misal: +put {TEMP_DATABASE} DatabaseOnRemote.kdbx +keluar +--- +{TEMP_DATABASE} digunakan sebagai penampung untuk menyimpan basis data di lokasi sementara +Perintah tersebut harus keluar. Dalam kasus `sftp` sebagai perintah terakhir, `keluar` harus dilakukan + + + + Timeout: + Waktu habis. + + + seconds + detik + + DatabaseTabWidget @@ -2330,6 +2601,11 @@ Masalah ini jelas sebuah bug, silakan laporkan ke pengembang. Database tab name modifier %1 [Dikunci] + + %1 [Temporary] + Database tab name modifier + %1 [Sementara] + DatabaseWidget @@ -2387,7 +2663,7 @@ Masalah ini jelas sebuah bug, silakan laporkan ke pengembang. Entries expiring within %1 day(s) - + Entri yang kedaluwarsa dalam waktu %1 hari(s) No current database. @@ -2453,26 +2729,6 @@ Simpan perubahan? File has changed Berkas telah berubah - - The database file has changed. Do you want to load the changes? - Berkas basis data telah berubah. Apakah Anda ingin memuat perubahannya? - - - Merge Request - Permintaan Penggabungan - - - The database file has changed and you have unsaved changes. -Do you want to merge your changes? - Berkas basis data telah berubah dan Anda memiliki ubahan yang belum disimpan. -Apakah Anda ingin menggabungkan ubahan Anda? - - - Could not open the new database file while attempting to autoreload. -Error: %1 - Tidak bisa membuka berkas basis data baru saat mencoba untuk memuat ulang. -Galat: %1 - Disable safe saves? Nonaktifkan penyimpanan aman? @@ -2524,6 +2780,86 @@ Nonaktifkan penyimpanan aman dan coba lagi? Database tab name modifier %1 [Basis Data Baru] + + Remote Sync did not contain any download or upload commands. + Sinkronisasi Jarak Jauh tidak berisi perintah unduh atau unggah. + + + Remote sync '%1' completed successfully! + Sinkronisasi jarak jauh '%1' berhasil diselesaikan! + + + Remote sync '%1' failed: %2 + Sinkronisasi jarak jauh '%1' gagal: %2 + + + Error while saving database %1: %2 + Kesalahan saat menyimpan basis data %1: %2 + + + Downloading... + Mengunduh... + + + Uploading... + Mengunggah... + + + Syncing... + Menyinkronkan... + + + Remove passkey from entry + Hapus kunci akses dari entri + + + Do you want to remove the passkey from this entry? + Apakah Anda ingin menghapus kunci akses dari entri ini? + + + The database file "%1" was modified externally + + + + Do you want to load the changes? + + + + Reload database + + + + Reloading database… + + + + Reload canceled + + + + Reload successful + + + + Reload pending user action… + + + + The database file "%1" was modified externally.<br>How would you like to proceed?<br><br>Merge all changes<br>Ignore the changes on disk until save<br>Discard unsaved changes + + + + The database file "%1" was modified externally.<br>How would you like to proceed?<br><br>Merge all changes then save<br>Overwrite the changes on disk<br>Discard unsaved changes + + + + Database file overwritten. + + + + Database file on disk cannot be unlocked with current credentials.<br>Enter new credentials and/or present hardware key to continue. + + EditEntryWidget @@ -2575,10 +2911,6 @@ Nonaktifkan penyimpanan aman dan coba lagi? n/a t/a - - (encrypted) - (terenkripsi) - Select private key Pilih kunci privat @@ -2667,7 +2999,7 @@ Would you like to correct it? %n hour(s) - + %n jam(s) %n week(s) @@ -2681,6 +3013,10 @@ Would you like to correct it? %n year(s) %n tahun + + Failed to decrypt SSH key, ensure password is correct. + Gagal mendekripsi kunci SSH, pastikan kata sandi sudah benar. + EditEntryWidgetAdvanced @@ -2852,18 +3188,10 @@ Would you like to correct it? Skip Auto-Submit for this entry Lewati Kirim-Otomatis untuk entri ini - - Only send this setting to the browser for HTTP Auth dialogs. If enabled, normal login forms will not show this entry for selection. - Hanya kirim pengaturan ini ke peramban untuk dialog Otentikasi HTTP. Jika diaktifkan, formulir masuk yang normal tidak akan menampilkan entri ini untuk dipilih. - Use this entry only with HTTP Basic Auth Hanya gunakan entri ini dengan Otentikasi Dasar HTTP - - Do not send this setting to the browser for HTTP Auth dialogs. If enabled, HTTP Auth dialogs will not show this entry for selection. - Do not send this setting to the browser for HTTP Auth dialogs. If enabled, HTTP Auth dialogs will not show this entry for selection. - Do not use this entry with HTTP Basic Auth Jangan gunakan entri ini dengan Otentikasi Dasar HTTP @@ -2882,11 +3210,19 @@ Would you like to correct it? These settings affect the entry's behaviour with the browser extension. - + Pengaturan ini memengaruhi perilaku entri dengan ekstensi peramban. Additional URLs - + URL Tambahan + + + Only send this entry to the browser for HTTP Auth dialogs. If enabled, normal login forms will not show this entry for selection. + Hanya kirim entri ini ke peramban untuk menampilkan jendela Autentikasi HTTP. Jika diaktifkan, halaman masuk normal tidak akan menampilkan entri ini untuk dipilih. + + + Do not send this entry to the browser for HTTP Auth dialogs. If enabled, HTTP Auth dialogs will not show this entry for selection. + Jangan kirim entri ini ke peramban untuk meminta Autentikasi HTTP. Jika diaktifkan, jendela Autentikasi HTTP tidak akan menampilkan entri ini untuk dipilih. @@ -3110,6 +3446,10 @@ Would you like to correct it? seconds detik + + Clear agent + + EditGroupWidget @@ -3202,11 +3542,11 @@ Would you like to correct it? Restrict matching to given browser key: - + Membatasi pencocokan dengan kunci peramban yang diberikan: Restrict matching to given browser key toggle for this and sub groups - + Batasi pencocokan dengan tombol kunci peramban yang diberikan untuk grup ini dan anak grup @@ -3474,7 +3814,7 @@ Ekstensi yang didukung adalah: %1. You can enable the DuckDuckGo website icon service under Application Settings -> Security - + Anda dapat mengaktifkan layanan ikon situs web DuckDuckGo melalui Pengaturan Aplikasi -> Keamanan @@ -3552,6 +3892,24 @@ Ini mungkin akan menyebabkan pengaya menjadi tidak berfungsi. %1 - Clone %1 - Salinan + + Passkey + Kunci akses + + + Invalid conversion type: %1 + Tipe konversi tidak valid: %1 + + + Invalid conversion syntax: %1 + Sintaks konversi tidak valid: %1 + + + Invalid regular expression syntax %1 +%2 + Sintaks ekspresi reguler %1 tidak valid +%2 + EntryAttachments @@ -3560,6 +3918,21 @@ Ini mungkin akan menyebabkan pengaya menjadi tidak berfungsi. Tidak bisa membuka berkas "%1" + + EntryAttachmentsDialog + + Form + Formulir + + + File name + + + + File contents... + + + EntryAttachmentsModel @@ -3597,14 +3970,6 @@ Ini mungkin akan menyebabkan pengaya menjadi tidak berfungsi. Remove Buang - - Rename selected attachment - Gantikan nama lampiran terpilih - - - Rename - Ganti namanya - Open selected attachment Buka lampiran yang dipilih @@ -3719,6 +4084,18 @@ Would you like to overwrite the existing attachment? Attachment "%1" already exists. Would you like to overwrite the existing attachment? + + New + + + + Preview + Pratinjau + + + Failed to preview an attachment: Attachment not found + + EntryAttributesModel @@ -3915,6 +4292,10 @@ Would you like to overwrite the existing attachment? Background Color + Warna Latar belakang + + + Group Path @@ -4279,7 +4660,7 @@ Anda dapat mengaktifkan layanan ikon situs web DuckDuckGo di bagian keamanan dal ImportWizard Import Wizard - + Panduan Impor @@ -4290,7 +4671,7 @@ Anda dapat mengaktifkan layanan ikon situs web DuckDuckGo di bagian keamanan dal Entry count: %1 - + Jumlah entri: %1 Group @@ -4310,6 +4691,14 @@ Anda dapat mengaktifkan layanan ikon situs web DuckDuckGo di bagian keamanan dal Url + Alamat web + + + Could not load key file. + Tidak dapat memuat berkas kunci. + + + Could not open remote database. Password or key file may be incorrect. @@ -4415,6 +4804,44 @@ Anda dapat mengaktifkan layanan ikon situs web DuckDuckGo di bagian keamanan dal KeePass1 Database + + Proton Pass (.json) + + + + Proton Pass JSON Export + + + + Temporary Database + + + + Command: + Perintah: + + + e.g.: "sftp user@hostname" or "scp user@hostname:DatabaseOnRemote.kdbx {TEMP_DATABASE}" + misalnya: "sftp user@hostname" atau "scp user@hostname:DatabaseOnRemote.kdbx {TEMP_DATABASE}" + + + Input: + Input: + + + e.g.: +get DatabaseOnRemote.kdbx {TEMP_DATABASE} +exit +--- +{TEMP_DATABASE} is used as placeholder to store the database in a temporary location +The command has to exit. In case of `sftp` as last commend `exit` has to be sent + + + + + Remote Database (.kdbx) + + KMessageWidget @@ -5555,12 +5982,6 @@ Versi ini tidak dimaksudkan untuk penggunaan sehari-hari. Expect some bugs and minor issues, this version is meant for testing purposes. CATATAN: Anda menggunakan versi pra-rilis KeePassXC. Ada beberapa kutu dan masalah-masalah kecil, versi ini ditujukan untuk penggunaan percobaan. - - - WARNING: Your Qt version may cause KeePassXC to crash with an On-Screen Keyboard. -We recommend you use the AppImage available on our downloads page. - WARNING: Your Qt version may cause KeePassXC to crash with an On-Screen Keyboard. -We recommend you use the AppImage available on our downloads page. No Tags @@ -5634,6 +6055,10 @@ We recommend you use the AppImage available on our downloads page. Import Passkey + + Remote S&ync… + + Quit Application @@ -5738,6 +6163,10 @@ We recommend you use the AppImage available on our downloads page. Show Password Generator + + Remove Passkey From Entry + + Perform Auto-Type: {USERNAME} @@ -5882,6 +6311,34 @@ We recommend you use the AppImage available on our downloads page. Toggle Allow Screen Capture + + Show Group Panel + + + + Toggle Show Group Panel + + + + Setup Remote Sync… + + + + Password Generator + Pembuat Sandi + + + E&xpire Entry… + + + + Clear SSH Agent + + + + Clear all identities in ssh-agent + + ManageDatabase @@ -6032,6 +6489,25 @@ We recommend you use the AppImage available on our downloads page. Silakan masukkan nama dan deskripsi opsional untuk basis data Anda yang baru: + + NewEntryAttachmentsDialog + + Attachment name cannot be empty + + + + Attachment with the same name already exists + + + + Save attachment + Simpan lampiran + + + New entry attachment + + + NixUtils @@ -6219,6 +6695,10 @@ We recommend you use the AppImage available on our downloads page. Unexpected EOF when writing private key EOF yang tidak terduga saat menulis kunci privat + + (encrypted) + (terenkripsi) + OpenSSHKeyGenDialog @@ -6303,7 +6783,7 @@ Do you want to overwrite it? Username: %1 - + Nama pengguna: %1 Group @@ -6335,7 +6815,7 @@ Do you want to overwrite it? Relying Party: %1 - + Pihak yang Mengandalkan: %1 Import the following passkey: @@ -6569,10 +7049,6 @@ The following data is missing: Also choose from: Juga pilih dari: - - Excluded characters: "0", "1", "l", "I", "O", "|", "﹒" - Karakter yang dikecualikan: "0", "1", "l", "I", "O", "|", "﹒" - Exclude look-alike characters Kecualikan karakter mirip @@ -6597,10 +7073,6 @@ The following data is missing: Word Count: Jumlah Kata: - - Character Count: - Cacah Karakter: - Word Case: Besar Kecil Kata: @@ -6613,10 +7085,6 @@ The following data is missing: Add custom wordlist Add custom wordlist - - character - karakter - Close Tutup @@ -6723,6 +7191,22 @@ Do you want to overwrite it? Special Characters Karakter Spesial + + passwordLength + + + + Characters: %1 + + + + MIXED case + + + + Excluded characters: "0", "1", "l", "I", "O", "|", "﹒", "B", "8", "G", "6" + + PasswordWidget @@ -6790,6 +7274,21 @@ Do you want to overwrite it? Press &Tab between characters + + PreviewEntryAttachmentsDialog + + Preview entry attachment + + + + No preview available + + + + Image format not supported + + + QMessageBox @@ -7468,10 +7967,6 @@ Do you want to overwrite it? Invalid word count %1 Jumlah kata tidak valid %1 - - The word list is too small (< 1000 items) - Daftar kata terlalu kecil (<1000 item) - Title for the entry. Judul entri. @@ -7616,10 +8111,6 @@ Do you want to overwrite it? Exit interactive mode. Keluar dari mode interaktif. - - Format to use when exporting. Available choices are 'xml' or 'csv'. Defaults to 'xml'. - Format yang digunakan ketika mengekspor. Pilihan yang tersedia adalah 'xml' atau 'csv'. Standarnya adalah 'xml'. - Exports the content of a database to standard output in the specified format. Ekspor konten dari basis data ke keluaran standar dalam format yang ditentukan. @@ -8208,18 +8699,6 @@ Kernel: %3 %4 file empty berkas kosong - - malformed string - lema rusak - - - missing closing quote - kehilangan tanda kutip tutup - - - %1: (row, col) %2,%3 - %1: (baris, kolom) %2,%3 - AES 256-bit AES 256-bit @@ -8664,13 +9143,89 @@ This option is deprecated, use --set-key-file instead. - Unsupported KDF type, cannot decrypt json file + Unknown passkeys error - Unknown passkeys error + Invalid KDF iterations, cannot decrypt json file + + Unsupported format, ensure your Bitwarden export is password-protected + + + + Only PBKDF and Argon2 are supported, cannot decrypt json file + + + + Reset Shortcuts + + + + Double click an action to change its shortcut + + + + Filter... + + + + Shortcut Conflict + + + + Shortcut %1 conflicts with '%2'. Overwrite shortcut? + + + + Cannot generate valid passphrases because the wordlist is too short + + + + Encrypted files are not supported. + + + + Proton Pass Import + + + + Delete plugin data? + Hapus data pengaya? + + + Delete plugin data from Entry(s)? + + + + Passkey + Kunci akses + + + Format to use when exporting. Available choices are 'xml', 'csv' or 'html'. Defaults to 'xml'. + + + + start minimized to the system tray + + + + malformed string, possible unescaped delimiter + + + + missing closing delimiter + + + + %1, row: %2, column: %3 + + + + Tags + Tag + QtIOCompressor @@ -8706,6 +9261,37 @@ This option is deprecated, use --set-key-file instead. Galat zlib internal: + + RemoteHandler + + Command `%1` did not finish in time. Process was killed. + + + + Failed to upload merged database. Command `%1` did not finish in time. Process was killed. + + + + Invalid download parameters provided. + + + + Command `%1` failed to download database. + + + + Invalid database pointer or upload parameters provided. + + + + Command `%1` exited with status code: %2 + + + + Failed to upload merged database. Command `%1` exited with status code: %2 + + + ReportsWidgetBrowserStatistics @@ -8772,6 +9358,10 @@ This option is deprecated, use --set-key-file instead. Exclude from reports Kecualikan dari laporan + + Expire Entry(s)… + + Only show entries that have a URL @@ -8788,36 +9378,33 @@ This option is deprecated, use --set-key-file instead. (Expired) + + Delete plugin data from Entry(s)… + + ReportsWidgetHealthcheck - Hover over reason to show additional details. Double-click entries to edit. - Layangi di atas alasan untuk menampilkan detail lanjutan. Klik dua kali pada entri untuk mengedit. + Show expired entries + - Bad - Password quality - Buruk + (Expired) + + + + Hover over reason to show additional details. Double-click entries to edit. + Layangi di atas alasan untuk menampilkan detail lanjutan. Klik dua kali pada entri untuk mengedit. Bad — password must be changed Buruk — kata sandi harus diubah - - Poor - Password quality - Buruk - Poor — password should be changed Kurang baik — kata sandi harus diubah - - Weak - Password quality - Lemah - Weak — consider changing the password Lemah — pertimbangkan untuk mengubah kata sandi @@ -8866,18 +9453,14 @@ This option is deprecated, use --set-key-file instead. Exclude from reports Kecualikan dari laporan - - Show expired entries - + + Expire Entry(s)… + Show entries that have been excluded from reports - - (Expired) - - ReportsWidgetHibp @@ -8973,6 +9556,10 @@ This option is deprecated, use --set-key-file instead. Exclude from reports Kecualikan dari laporan + + Expire Entry(s)… + + ReportsWidgetPasskeys @@ -9214,6 +9801,14 @@ This option is deprecated, use --set-key-file instead. No agent running, cannot list identities. Tidak ada agen yang berjalan, tidak dapat mendaftarkan identitas. + + Failed to remove all SSH identities from agent. + + + + All SSH identities removed from agent. + + SearchHelpWidget @@ -9499,29 +10094,6 @@ This option is deprecated, use --set-key-file instead. Ekspor ke %1 - - ShortcutSettingsWidget - - Double click an action to change its shortcut - - - - Shortcut Conflict - - - - Filter... - - - - Shortcut %1 conflicts with '%2'. Overwrite shortcut? - - - - Reset Shortcuts - - - TagModel @@ -9811,11 +10383,15 @@ Contoh: JBSWY3DPEHPK3PXP Tidak mendeteksi kunci perangkat keras - <p>If you own a <a href="https://www.yubico.com/">YubiKey</a> or <a href="https://onlykey.io">OnlyKey</a>, you can use it for additional security.</p><p>The key requires one of its slots to be programmed as <a href="https://docs.yubico.com/yesdk/users-manual/application-otp/challenge-response.html">HMAC-SHA1 Challenge-Response</a>.</p> + Refresh hardware keys - Refresh hardware keys + <p>If you own a <a href="https://www.yubico.com/">YubiKey</a> or <a href="https://onlykey.io">OnlyKey</a>, you can use it for additional security.</p><p>The key requires one of its slots to be programmed with <a href="https://keepassxc.org/docs/#faq-yubikey-howto">Challenge-Response</a>.</p> + + + + Hardware keys found, but no slots are configured diff --git a/share/translations/keepassxc_it.ts b/share/translations/keepassxc_it.ts index f00f56937..e2348b0db 100644 --- a/share/translations/keepassxc_it.ts +++ b/share/translations/keepassxc_it.ts @@ -217,18 +217,50 @@ You must restart the application to set the new language. Would you like to restart now? Per impostare la nuova lingua è necessario riavviare l'applicazione. Vuoi riavviare ora? - - Reset Settings? - Vuoi ripristinare le impostazioni? - - - Are you sure you want to reset all general and security settings to default? - Sei sicuro di voler ripristinare tutte le impostazioni generali e di sicurezza predefinite? - Select backup storage directory Seleziona cartella salvataggio backup + + Confirm Reset + Conferma il ripristino + + + Are you sure you want to reset all settings to default? + Sei sicuro di voler ripristinare tutte le impostazioni ai valori predefiniti? + + + Import KeePassXC Settings + Importa impostazioni KeePassXC + + + Failed to import settings from %1, not a valid settings file. + Impossibile importare le impostazioni da %1, non è un file di impostazioni valido. + + + Export KeePassXC Settings + Esporta impostazioni KeePassXC + + + Small + Piccolo + + + Normal + Normale + + + Medium + Medio + + + Large + Grande + + + Custom + Personalizzato + ApplicationSettingsWidgetGeneral @@ -280,25 +312,6 @@ Include beta releases when checking for updates Includi versioni beta durante il controllo della disponibilità di aggiornamenti - - On database unlock, show entries that - Allo sblocco del database, visualizza le voci che - - - have expired - On database unlock, show entries that... - sono scaduti - - - days - On database unlock, show entries that will expire within %1 days - Giorni - - - will expire within - On database unlock, show entries that... - scadranno entro - File Management Gestione dei file @@ -323,22 +336,10 @@ Backup database file before saving Effettua una copia di sicurezza del database prima di salvarlo - - Backup destination - Destinazione backup - - - Specifies the database backup file location. Occurrences of "{DB_FILENAME}" are replaced with the filename of the saved database without extension. {TIME:<format>} is replaced with the backup time, see https://doc.qt.io/qt-5/qdatetime.html#toString. <format> defaults to format string "dd_MM_yyyy_hh-mm-ss". - Specifica il percorso del file di backup del database. Le occorrenze di "{DB_FILENAME}" vengono sostituite con il nome del file del database salvato senza estensione. {TIME:<format>} viene sostituito con l'ora di backup, vedi https://doc.qt.io/qt-5/qdatetime.html#toString. <format>per impostazione predefinita, formatta la stringa "dd_MM_yyyy_hh-mm-ss". - {DB_FILENAME}.old.kdbx {DB_FILENAME}.old.kdbx - - Choose... - Scegli... - Use alternative saving method (may solve problems with Dropbox, Google Drive, GVFS, etc.) Usa un metodo di salvataggio alternativo (può risolvere problemi con Dropbox, Google Drive, GVFS, ecc.) @@ -505,6 +506,71 @@ Remember last typed entry for: Ricorda l'ultima voce digitata per: + + On database unlock, show entries that will expire within + Allo sblocco del database, mostra le voci che scadranno entro + + + On database unlock, show entries that will expire within + Allo sblocco del database, mostra le voci che scadranno entro + + + days + number of days warning for password expiration + Giorni + + + Destination format: + Formato destinazione: + + + <html><head/><body><p><span style=" font-weight:600;">{DB_FILENAME}</span> is replaced with the filename of the saved database without extension</p><p><span style=" font-weight:600;">{TIME:&lt;format&gt;}</span> is replaced with the specified time format (default: dd_MM_yyyy_hh-mm-ss)</p><p>See the User Guide for more details</p></body></html> + <html><head/><body><p><span style=" font-weight:600;">{DB_FILENAME}</span>viene sostituito con il nome del file del database salvato senza estensione</p><p><span style=" font-weight:600;">{TIME:&lt;format&gt;}</span> viene sostituito con il formato orario specificato (predefinito: dd_MM_yyyy_hh-mm-ss)</p><p>vedere la Guida per l'utente per maggiori dettagli</p></body></html> + + + Choose folder... + Scegli cartella... + + + Show confirmation before moving entries to recycle bin + Visualizza la conferma prima di spostare le voci nel cestino + + + Copy data on double clicking field in entry view + Copia i dati facendo doppio clic sul campo nella vista della voce + + + Show toolbar + Visualizza barra strumenti + + + Show the menu bar by pressing the Alt key + Visualizza la barra dei menu premendo il tasto Alt + + + Show menubar + Mostra barra dei menu + + + Import settings… + Importa impostazioni... + + + Export settings… + Esporta impostazioni... + + + Open browser on double clicking URL field in entry view + Aprire il browser facendo doppio clic sul campo URL nella vista della voce + + + Font size: + Dimensione carattere: + + + Font size selection + Selezione dimensione carattere + ApplicationSettingsWidgetSecurity @@ -570,18 +636,6 @@ Hide passwords in the entry preview panel Nascondi la password nel pannello di anteprima della voce - - Hide entry notes by default - per impostazione predefinita nascondi le note della voce - - - Move entries to recycle bin without confirmation - Sposta le voci nel cestino senza conferma - - - Enable double click to copy the username/password entry columns - Abilita il doppio clic per copiare le colonne di immissione nome utente/password - Privacy Riservatezza @@ -594,6 +648,18 @@ Hide TOTP in the entry preview panel Nascondi TOTP nel pannello di anteprima della voce + + Lock databases when switching user + Blocca il database quando si cambia utente + + + Lock Options + Opzioni di blocco + + + Hide notes in the entry preview panel + Nascondi le note nel pannello di anteprima della voce + AutoType @@ -643,20 +709,6 @@ Se hai già concesso il permesso, riavvia KeePassXC. Entry does not have attribute for PICKCHARS: %1 La voce non ha l'attributo per PICKCHARS: %1 - - Invalid conversion type: %1 - Tipo di conversione non valido: %1 - - - Invalid conversion syntax: %1 - Sintassi di conversione non valida: %1 - - - Invalid regular expression syntax %1 -%2 - Sintassi della espressione regolare non valida %1 -%2 - Invalid placeholder: %1 Segnaposto non valido: %1 @@ -716,7 +768,7 @@ Se hai già concesso il permesso, riavvia KeePassXC. Trying to send invalid keyboard symbol. - + Tentativo di invio di un simbolo non valido. @@ -883,24 +935,25 @@ Seleziona il database corretto dove salvare le credenziali. Add to existing entry - + Aggiungi a voce esistente Existing passkey found. Do you want to register a new passkey for: - + Trovata una passkey esistente. +Vuoi registrare una nuova passkey per: Select the existing passkey and press Update to replace it. - + Seleziona la passkey esistente e premi Aggiorna per sostituirla. Authenticate passkey credentials for: - + Autentica credenziali passkey per: Do you want to register a passkey for: - + Vuoi registrare una passkey per: @@ -984,16 +1037,17 @@ Vuoi eliminare questa voce? Register a new passkey to this entry: - + Registra una nuova passkey per questa voce: KeePassXC - Update passkey - + KeePassXC - Aggiorna passkey Entry already has a passkey. Do you want to overwrite the passkey in %1 - %2? - + La voce possiede già una passkey. +Vuoi sovrascrivere la passkey in %1 - %2? Register @@ -1018,10 +1072,6 @@ Do you want to overwrite the passkey in %1 - %2? General Generale - - Browsers installed as snaps are currently not supported. - I browser installati come snap non sono attualmente supportati. - Enable integration for these browsers: Abilita integrazione per i seguenti browser: @@ -1193,18 +1243,6 @@ Do you want to overwrite the passkey in %1 - %2? Custom extension ID ID estensione personalizzata - - Due to Snap sandboxing, you must run a script to enable browser integration.<br />You can obtain this script from %1 - A causa del sandboxing di Snap, per abilitare l'integrazione del browser è necessario eseguire uno script. <br />È possibile ottenere questo script da %1 - - - KeePassXC-Browser is needed for the browser integration to work. <br />Download it for %1 and %2 and %3. %4 - Per far funzionare l'integrazione del browser KeePassXC-Browser. <br />Scaricarlo per %1, %2 e %3. %4 - - - Please see special instructions for browser extension use below - Per l'uso dell'estensione del browser di seguito consulta le istruzioni speciali - Executable Files File eseguibili @@ -1247,11 +1285,19 @@ Do you want to overwrite the passkey in %1 - %2? Allows using insecure http://localhost with passkeys for testing purposes. - + Permetti di utilizzare http://localhost (insicuro) con le passkeys per fini di test. Allow using localhost with passkeys - + Permetti di utilizzare localhost con le passkeys + + + KeePassXC-Browser is needed for the browser integration to work. <br />Download it for %1 and %2 and %3. + KeePassXC-Browser è necessario per il funzionamento dell'integrazione con il browser. Scaricalo per %1, %2 e %3. + + + Browsers installed using Snap or Flatpak are not supported with exception to Firefox installed using Snap. + I browser installati tramite Snap o Flatpak non sono supportati, ad eccezione di Firefox installato tramite Snap. @@ -1395,6 +1441,20 @@ Do you want to overwrite the passkey in %1 - %2? Imported from CSV file: %1 Importato da file CSV: %1 + + No Title Selected + Nessun Titolo Selezionato + + + No title column was selected, entries will be hard to tell apart. +Are you sure you want to import? + Non è stata selezionata alcuna colonna del titolo, le voci saranno difficili da distinguere. +Sei sicuro di voler importare? + + + Tags + Etichette + CsvParserModel @@ -1458,6 +1518,14 @@ Database di backup che si trova in %2 Recycle Bin Cestino + + Database file read error. + Errore di lettura del file del database. + + + No file path was provided. + Non è stato fornito alcun percorso del file. + DatabaseOpenDialog @@ -1604,15 +1672,7 @@ Per evitare che questo errore venga visualizzato, è necessario andare alle &quo <p>In addition to a password, you can use a secret file to enhance the security of your database. This file can be generated in your database's security settings.</p><p>This is <strong>not</strong> your *.kdbx database file!</p> - - - - Click to add a key file. - Clicca per aggiungere un file chiave. - - - <a href="#" style="text-decoration: underline">I have a key file</a> - + <p>Oltre ad una password, puoi utilizzare un file segreto per migliorare la sicurezza del tuo database. Questo file può essere generato nelle impostazioni di sicurezza del tuo database.</p><p>Questo<strong>non</strong>è il tuo file database *.kdbx!</p> Use hardware key [Serial: %1] @@ -1637,7 +1697,10 @@ Se non hai un file key o non sai cosa sia, non selezionarlo. A database file is NOT a key file! Are you sure you want to continue with this file?. - + Il file selezionato sembra essere un file database. +Un file database NON è un file chiave. + +Sei sicuro di voler continuare con questo file? No hardware keys found. @@ -1647,6 +1710,18 @@ Are you sure you want to continue with this file?. Refresh Hardware Keys Aggiorna tasti hardware + + Click to add a key file. + Clicca per aggiungere un file chiave. + + + <a href="#" style="text-decoration: underline">I have a key file</a> + <a href="#" style="text-decoration: underline">Ho un file chiave</a> + + + Hardware keys found, but no slots are configured. + Chiave hardware trovata, ma non è configurato nessuno slot. + DatabaseSettingWidgetMetaData @@ -1681,6 +1756,22 @@ Are you sure you want to continue with this file?. Maintenance Manutenzione + + KeeShare + KeeShare + + + Secret Service Integration + Integrazione Secret Service + + + Remote Sync + Sincronizzazione Remota + + + Database Settings: %1 + Impostazioni database: %1 + DatabaseSettingsWidgetBrowser @@ -1851,14 +1942,14 @@ Vuoi continuare senza password? Weak password Password debole - - You must enter a stronger password to protect your database. - Devi inserire una password più forte per proteggere il database. - This is a weak password! For better protection of your secrets, you should choose a stronger password. Questa è una password debole. Per una maggiore protezione dei segreti, dovresti scegliere una password più forte. + + The provided password does not meet the minimum quality requirement. + La password fornita non rispetta i requisiti qualitativi minimi. + DatabaseSettingsWidgetEncryption @@ -2160,6 +2251,50 @@ rimosse dal database. Autosave delay since last change checkbox Casella di controllo per l'intervallo di salvataggio automatico dall'ultimo cambiamento + + Public Database Metadata + Metadati del database pubblico + + + Warning: the following settings are not encrypted. + Attenzione: le seguenti impostazioni non sono crittografate. + + + Display name: + Nome di visualizzazione: + + + Publically visible display name used on the unlock dialog + Nome visualizzato visibile pubblicamente utilizzato nella finestra di dialogo di sblocco + + + Database public display name + Nome pubblico del database visualizzato + + + Display color: + Colore di visualizzazione: + + + Publically visible color used on the unlock dialog + Colore visibile pubblicamente utilizzato nella finestra di dialogo di sblocco + + + Database public display color chooser + Selettore colore display pubblico del database + + + Clear + Azzera + + + Display icon: + Simbolo di visualizzazione: + + + Select Database Icon + Seleziona l'icona del database + DatabaseSettingsWidgetKeeShare @@ -2255,6 +2390,141 @@ rimosse dal database. Campo descrizione database + + DatabaseSettingsWidgetRemote + + Sync Commands + Comandi Sincronizzazione + + + Remove + Rimuovi + + + Command Settings + Impostazioni Comando + + + Name + Nome + + + Save + Salva + + + Download + Download + + + Command: + Comando: + + + Download command field + Scarica il campo del comando + + + e.g.: "sftp user@hostname" or "scp user@hostname:DatabaseOnRemote.kdbx {TEMP_DATABASE}" + es.: "sftp user@hostname" oppure "scp user@hostname:DatabaseOnRemote.kdbx {TEMP_DATABASE}" + + + Input: + Input: + + + Download input field + Scarica il campo di input + + + Upload + Caricare + + + Upload command field + Carica il campo del comando + + + e.g.: "sftp user@hostname" or "scp {TEMP_DATABASE} user@hostname:DatabaseOnRemote.kdbx" + Ad esempio.: "sftp user@hostname" o "scp {TEMP_DATABASE} user@hostname:DatabaseOnRemote.kdbx" + + + Upload input field + Carica il campo di input + + + Name cannot be empty. + Il nome non può essere vuoto. + + + Test + Test + + + Download command cannot be empty. + Il comando di download non può essere vuoto. + + + Download failed with error: %1 + Download non riuscito con errore: %1 + + + Download finished, but file %1 could not be found. + Download completato, ma il file %1 non è stato trovato. + + + Download successful. + Download completato con successo. + + + Save Remote Settings + Salva impostazioni remote + + + You have unsaved changes. Do you want to save them? + Hai delle modifiche non salvate. Vuoi salvarle? + + + e.g.: +get DatabaseOnRemote.kdbx {TEMP_DATABASE} +exit +--- +{TEMP_DATABASE} is used as placeholder to store the database in a temporary location +The command has to exit. In case of `sftp` as last command `exit` has to be sent + + ad es.: +get DatabaseOnRemote.kdbx {TEMP_DATABASE} +exit +--- +{TEMP_DATABASE} è utilizzato come segnaposto per memorizzare il database in una posizione temporanea +Il comando deve uscire. In caso di `sftp` come ultimo comando `exit` deve essere inviato + + + + e.g.: +put {TEMP_DATABASE} DatabaseOnRemote.kdbx +exit +--- +{TEMP_DATABASE} is used as placeholder to store the database in a temporary location +The command has to exit. In case of `sftp` as last command `exit` has to be sent + + ad es.: +put {TEMP_DATABASE} DatabaseOnRemote.kdbx +exit +--- +{TEMP_DATABASE} è utilizzato come segnaposto per memorizzare il database in una posizione temporanea +Il comando deve uscire. In caso di `sftp` come ultimo comando `exit` deve essere inviato + + + + Timeout: + Timeout: + + + seconds + secondi + + DatabaseTabWidget @@ -2328,6 +2598,11 @@ Questo è sicuramente un bug, segnalalo agli sviluppatori. Database tab name modifier %1 [bloccato] + + %1 [Temporary] + Database tab name modifier + %1 [Temporary] + DatabaseWidget @@ -2451,26 +2726,6 @@ Vuoi salvare le modifiche? File has changed Il file è stato modificato - - The database file has changed. Do you want to load the changes? - Il file del database è stato modificato. Vuoi caricare le modifiche? - - - Merge Request - Richiesta di unione - - - The database file has changed and you have unsaved changes. -Do you want to merge your changes? - Il file del database è stato cambiato e ci sono cambiamenti non salvati -Vuoi unire le modifiche? - - - Could not open the new database file while attempting to autoreload. -Error: %1 - Impossibile aprire il nuovo file database durante il tentativo di ricaricamento. -Errore: %1 - Disable safe saves? Disabilita i salvataggi sicuri? @@ -2522,6 +2777,86 @@ Vuoi disabilitare i salvataggi sicuri e riprovare? Database tab name modifier %1 [nuovo database] + + Remote Sync did not contain any download or upload commands. + La sincronizzazione remota non conteneva alcun comando di download o upload. + + + Remote sync '%1' completed successfully! + Sincronizzazione remota '%1' completata con successo! + + + Remote sync '%1' failed: %2 + Sincronizzazione remota '%1' fallita: %2 + + + Error while saving database %1: %2 + Errore durante il salvataggio del database %1: %2 + + + Downloading... + Scaricamento... + + + Uploading... + Caricamento... + + + Syncing... + Sincronizzazione... + + + Remove passkey from entry + Rimuovi passkey dalla voce + + + Do you want to remove the passkey from this entry? + Vuoi rimuovere la passkey da questa voce? + + + The database file "%1" was modified externally + Il file di database "%1" è stato modificato esternamente + + + Do you want to load the changes? + Vuoi caricare le modifiche? + + + Reload database + Ricarica il database + + + Reloading database… + Ricaricamento del database… + + + Reload canceled + Ricaricamento annullato + + + Reload successful + Ricaricamento completato correttamente + + + Reload pending user action… + Ricaricamento in attesa di azione dell'utente... + + + The database file "%1" was modified externally.<br>How would you like to proceed?<br><br>Merge all changes<br>Ignore the changes on disk until save<br>Discard unsaved changes + Il file di database "%1" è stato modificato esternamente.<br> Come desideri procedere?<br><br>Unisci tutte le modifiche<br>Ignora le modifiche sul disco fino al salvataggio<br>Ignora le modifiche non salvate + + + The database file "%1" was modified externally.<br>How would you like to proceed?<br><br>Merge all changes then save<br>Overwrite the changes on disk<br>Discard unsaved changes + Il file di database "%1" è stato modificato esternamente.<br>Come desideri procedere?<br><br>Unisci tutte le modifiche, quindi salva<br>Sovrascrivi le modifiche sul disco<br>Ignora le modifiche non salvate + + + Database file overwritten. + File di database sovrascritto. + + + Database file on disk cannot be unlocked with current credentials.<br>Enter new credentials and/or present hardware key to continue. + Il file del database sul disco non può essere sbloccato con le credenziali attuali.<br> Digita le nuove credenziali e/o presenta la chiave hardware per continuare. + EditEntryWidget @@ -2573,10 +2908,6 @@ Vuoi disabilitare i salvataggi sicuri e riprovare? n/a n/a - - (encrypted) - (cifrato) - Select private key Seleziona chiave privata @@ -2679,6 +3010,10 @@ Vuoi correggerla? %n year(s) %n anno%n anni%n anni + + Failed to decrypt SSH key, ensure password is correct. + Impossibile decriptare la chiave SSH, assicurati che la password sia corretta. + EditEntryWidgetAdvanced @@ -2850,18 +3185,10 @@ Vuoi correggerla? Skip Auto-Submit for this entry Ignora invio automatico per questa voce - - Only send this setting to the browser for HTTP Auth dialogs. If enabled, normal login forms will not show this entry for selection. - Manda queste impostazioni al browser solo solo per l'autenticazione HTTP. Se abilitata, la pagina di login non mostrerà questa voce disponibile per la selezione. - Use this entry only with HTTP Basic Auth Usa questa voce solo con l'autenticazione semplice HTTP - - Do not send this setting to the browser for HTTP Auth dialogs. If enabled, HTTP Auth dialogs will not show this entry for selection. - Non inviare questa impostazione al browser per le finestre di dialogo autenticazione HTTP. Se attivata, le finestre di dialogo autenticazione HTTP non mostreranno questa voce per la selezione. - Do not use this entry with HTTP Basic Auth Non usare questa voce con l'autenticazione semplice HTTP @@ -2880,11 +3207,19 @@ Vuoi correggerla? These settings affect the entry's behaviour with the browser extension. - + Queste impostazioni influenzano il comportamento della voce con l'estensione browser. Additional URLs - + URL aggiuntive + + + Only send this entry to the browser for HTTP Auth dialogs. If enabled, normal login forms will not show this entry for selection. + Invia questa voce esclusivamente per finestre HTTP Auth. Se abilitato, le form di login normali non mostreranno questa voce come voce selezionabile. + + + Do not send this entry to the browser for HTTP Auth dialogs. If enabled, HTTP Auth dialogs will not show this entry for selection. + Non inviare questa voce al browser per finestre HTTP Auth. Se abilitato, le finestre HTTP Auth non mostreranno questa voce come voce selezionabile. @@ -3108,6 +3443,10 @@ Vuoi correggerla? seconds secondi + + Clear agent + Cancella agent + EditGroupWidget @@ -3550,6 +3889,24 @@ Questo potrebbe causare malfunzionamenti ai plugin interessati. %1 - Clone %1 - clone + + Passkey + Passkey + + + Invalid conversion type: %1 + Tipo di conversione non valido: %1 + + + Invalid conversion syntax: %1 + Sintassi di conversione non valida: %1 + + + Invalid regular expression syntax %1 +%2 + Sintassi della espressione regolare non valida %1 +%2 + EntryAttachments @@ -3558,6 +3915,21 @@ Questo potrebbe causare malfunzionamenti ai plugin interessati. Impossibile aprire il file "%1" + + EntryAttachmentsDialog + + Form + Modulo + + + File name + Nome file + + + File contents... + Contenuto del file... + + EntryAttachmentsModel @@ -3595,14 +3967,6 @@ Questo potrebbe causare malfunzionamenti ai plugin interessati. Remove Rimuovi - - Rename selected attachment - Rinomina l'allegato selezionato - - - Rename - Rinominare - Open selected attachment Apri allegato selezionato @@ -3719,6 +4083,18 @@ Would you like to overwrite the existing attachment? L'allegato "%1" esiste già. Vuoi sovrascrivere l'allegato esistente? + + New + Nuovo + + + Preview + Anteprima + + + Failed to preview an attachment: Attachment not found + Impossibile visualizzare l'anteprima di un allegato: allegato non trovato + EntryAttributesModel @@ -3917,6 +4293,10 @@ Vuoi sovrascrivere l'allegato esistente? Background Color Colore di sfondo + + Group Path + Percorso del Gruppo + EntryPreviewWidget @@ -4312,6 +4692,14 @@ You can enable the DuckDuckGo website icon service in the security section of th Url Url + + Could not load key file. + Impossibile caricare il file chiave. + + + Could not open remote database. Password or key file may be incorrect. + Impossibile aprire il database remoto. La password o il file chiave potrebbero essere errati. + ImportWizardPageSelect @@ -4365,7 +4753,7 @@ You can enable the DuckDuckGo website icon service in the security section of th 1Password Vault (.opvault) - + Vault 1Password (.opvault) Bitwarden (.json) @@ -4415,6 +4803,50 @@ You can enable the DuckDuckGo website icon service in the security section of th KeePass1 Database Database KeePass1 + + Proton Pass (.json) + Proton Pass (.json) + + + Proton Pass JSON Export + Esportazione Proton Pass JSON + + + Temporary Database + Database temporaneo + + + Command: + Comando: + + + e.g.: "sftp user@hostname" or "scp user@hostname:DatabaseOnRemote.kdbx {TEMP_DATABASE}" + es.: "sftp user@hostname" oppure "scp user@hostname:DatabaseOnRemote.kdbx {TEMP_DATABASE}" + + + Input: + Input: + + + e.g.: +get DatabaseOnRemote.kdbx {TEMP_DATABASE} +exit +--- +{TEMP_DATABASE} is used as placeholder to store the database in a temporary location +The command has to exit. In case of `sftp` as last commend `exit` has to be sent + + ad es.: +get DatabaseOnRemote.kdbx {TEMP_DATABASE} +exit +--- +{TEMP_DATABASE} è utilizzato come segnaposto per memorizzare il database in una posizione temporanea +Il comando deve uscire. In caso di `sftp` come ultimo comando `exit` deve essere inviato + + + + Remote Database (.kdbx) + Database remoto (.kdbx) + KMessageWidget @@ -5500,7 +5932,7 @@ Sei sicuro di voler continuare con questo file? Show Menubar - + Mostra barra dei menù Show Toolbar @@ -5555,12 +5987,6 @@ Questa versione non è destinata all'uso in produzione. Expect some bugs and minor issues, this version is meant for testing purposes. NOTA: stai usando una versione non definitiva di KeePassXC. Aspettatevi alcuni bug e problemi minori, questa versione è pensata per scopi di test. - - - WARNING: Your Qt version may cause KeePassXC to crash with an On-Screen Keyboard. -We recommend you use the AppImage available on our downloads page. - ATTENZIONE: la versione di Qt potrebbe causare l'arresto anomalo di KeePassXC con una tastiera su schermo. -Ti consigliamo di usare l'AppImage disponibile sulla nostra pagina download. No Tags @@ -5634,6 +6060,10 @@ Ti consigliamo di usare l'AppImage disponibile sulla nostra pagina download Import Passkey Importa Passkey + + Remote S&ync… + S&incronizzazione Remota... + Quit Application Esci dall'applicazione @@ -5738,6 +6168,10 @@ Ti consigliamo di usare l'AppImage disponibile sulla nostra pagina download Show Password Generator Mostra generatore di password + + Remove Passkey From Entry + Rimuovi Passkey Dalla Voce + Perform Auto-Type: {USERNAME} Esegui digitazione automatica: {USERNAME} @@ -5816,7 +6250,7 @@ Ti consigliamo di usare l'AppImage disponibile sulla nostra pagina download Open Keyboard Shortcuts Guide - + Apri Guida Scorciatoie Tastiera Save Database Backup @@ -5824,11 +6258,11 @@ Ti consigliamo di usare l'AppImage disponibile sulla nostra pagina download SSH Agent: Add Key - + SSH Agent: Aggiungi Chiave SSH Agent: Remove Key - + Agent SSH: Rimuovi Chiave Toggle Compact Mode @@ -5852,7 +6286,7 @@ Ti consigliamo di usare l'AppImage disponibile sulla nostra pagina download Toggle Show Menubar - + Abilita Mostra la barra dei menù Toggle Show Toolbar @@ -5882,6 +6316,34 @@ Ti consigliamo di usare l'AppImage disponibile sulla nostra pagina download Toggle Allow Screen Capture Consenti cattura schermo + + Show Group Panel + Mostra pannello del gruppo + + + Toggle Show Group Panel + Attiva/disattiva 'Visualizza pannello del gruppo' + + + Setup Remote Sync… + Imposta Sincronizzazione Remota... + + + Password Generator + Genera password + + + E&xpire Entry… + Sca&denza voce… + + + Clear SSH Agent + Cancella SSH Agent + + + Clear all identities in ssh-agent + Cancella tutte le identità in ssh-agent + ManageDatabase @@ -6032,6 +6494,25 @@ Ti consigliamo di usare l'AppImage disponibile sulla nostra pagina download Compila il nome visualizzato e una descrizione facoltativa per il nuovo database: + + NewEntryAttachmentsDialog + + Attachment name cannot be empty + Il nome dell'allegato non può essere vuoto + + + Attachment with the same name already exists + Esiste già un allegato con lo stesso nome + + + Save attachment + Salva allegato + + + New entry attachment + Nuovo allegato di ingresso + + NixUtils @@ -6219,6 +6700,10 @@ Ti consigliamo di usare l'AppImage disponibile sulla nostra pagina download Unexpected EOF when writing private key EOF imprevisto durante la scrittura di una chiave privata + + (encrypted) + (cifrato) + OpenSSHKeyGenDialog @@ -6267,7 +6752,7 @@ Ti consigliamo di usare l'AppImage disponibile sulla nostra pagina download Export the following passkey entries. - + Esporta le voci passkey seguenti. @@ -6341,15 +6826,15 @@ Vuoi sovrascriverlo? Import the following passkey: - + Importa la seguente passkey: Import the following passkey to this entry: - + Importa la passkey seguente in questa voce: Default passkeys group (Imported Passkeys) - + Gruppo passkeys predefinito (Passkeys Importate) @@ -6372,25 +6857,27 @@ Vuoi sovrascriverlo? Open passkey file - + Apri file passkey Cannot import passkey - + Impossibile importare passkey Cannot import passkey file "%1". Data is missing. - + Impossibile importare il file passkey "%1". Mancano i dati. Cannot import passkey file "%1". The following data is missing: %2 - + Impossibile importare il file passkey "%1". +I dati seguenti mancano: +%2 Cannot import passkey file "%1". Private key is missing or malformed. - + Impossibile importare il file passkey "%1". La chiave privata è mancante o malformata. @@ -6571,10 +7058,6 @@ The following data is missing: Also choose from: Scegli anche tra: - - Excluded characters: "0", "1", "l", "I", "O", "|", "﹒" - Caratteri esclusi: "0", "1", "l", "I", "O", "|", "﹒" - Exclude look-alike characters Escludi caratteri simili @@ -6599,10 +7082,6 @@ The following data is missing: Word Count: Conteggio parole: - - Character Count: - Conteggio caratteri: - Word Case: Parole maiuscole/minuscole: @@ -6615,10 +7094,6 @@ The following data is missing: Add custom wordlist Aggiungi elenco parole personalizzato - - character - Carattere - Close Chiudi @@ -6725,6 +7200,22 @@ Vuoi sovrascriverlo? Special Characters Caratteri speciali + + passwordLength + passwordLength + + + Characters: %1 + Caratteri :%1 + + + MIXED case + lettere maiuscole e minuscole + + + Excluded characters: "0", "1", "l", "I", "O", "|", "﹒", "B", "8", "G", "6" + Caratteri esclusi: "0", "1", "l", "I", "O", "|", "﹒", "B", "8", "G", "6" + PasswordWidget @@ -6792,6 +7283,21 @@ Vuoi sovrascriverlo? Premi &Tab tra i caratteri + + PreviewEntryAttachmentsDialog + + Preview entry attachment + Anteprima dell'allegato della voce + + + No preview available + Nessuna anteprima disponibile + + + Image format not supported + Formato immagine non supportato + + QMessageBox @@ -7471,10 +7977,6 @@ Usa '--stdout' o specifica un 'file-esportazione'.Invalid word count %1 Conteggio parole non valido %1 - - The word list is too small (< 1000 items) - L'elenco delle parole è troppo piccolo (< 1000 voci) - Title for the entry. Titolo di una voce. @@ -7619,10 +8121,6 @@ Usa '--stdout' o specifica un 'file-esportazione'.Exit interactive mode. Uscire dalla modalità interattiva. - - Format to use when exporting. Available choices are 'xml' or 'csv'. Defaults to 'xml'. - Formato usabile per l'esportazione. È possibile scegliere tra 'xml' e 'csv'. L'impostazione predefinita è 'xml'. - Exports the content of a database to standard output in the specified format. Esporta il contenuto di un database nell'output standard nel formato specificato. @@ -8210,18 +8708,6 @@ Kernel: %3 %4 file empty file vuoto - - malformed string - stringa non valida - - - missing closing quote - virgoletta di chiusura mancante - - - %1: (row, col) %2,%3 - %1: (riga, col) %2,%3 - AES 256-bit AES 256-bit @@ -8465,11 +8951,12 @@ Kernel: %3 %4 Set the key file for the database. This option is deprecated, use --set-key-file instead. - + Imposta il file chiave per il database. +Questa opzione è deprecata, utilizza invece --set-key-file. Databases have been locked. - + I databases sono stati bloccati. Attestation not supported @@ -8561,27 +9048,27 @@ This option is deprecated, use --set-key-file instead. Effective domain is not a valid domain - + Il dominio effettivo non è un dominio valido Origin and RP ID do not match - + Origin e RP ID non corrispondono No supported algorithms were provided - + Nessun algoritmo supportato è stato fornito Wait for timer to expire - + Attendi la scadenza del timer Challenge is shorter than required minimum length - + La sfida è inferiore alla lunghezza minima richiesta user.id does not match the required length - + user.id non corrisponde alla lunghezza richiesta Favorite @@ -8598,19 +9085,19 @@ This option is deprecated, use --set-key-file instead. Cannot parse file: %1 at position %2 - + Impossibile processare il file: %1 alla posizione %2 Failed to decrypt json file: %1 - + Impossibile decriptare il file json: %1 Invalid encKeyValidation field - + Campo encKeyValidation non valido Invalid cipher list within encKeyValidation field - + Elenco di cifrari non valido nel campo encKeyValidation Wrong password @@ -8618,15 +9105,15 @@ This option is deprecated, use --set-key-file instead. Invalid encrypted data field - + Campo dati cifrati non valido Invalid cipher list within encrypted data field - + Elenco di cifrari non valido nel campo dati cifrato Cannot initialize cipher - + Impossibile inizializzare il cifrario Cannot decrypt data @@ -8643,11 +9130,11 @@ This option is deprecated, use --set-key-file instead. Invalid 1PUX file format: Not a valid ZIP file. - + Formato file 1PUX non valido. Non è un file ZIP valido. Invalid 1PUX file format: Missing export.data - + Formato file 1PUX non valido. Manca export.data 1Password Import @@ -8655,23 +9142,99 @@ This option is deprecated, use --set-key-file instead. Enter Shortcut - + Inserisci scorciatoia Action - + Azione Shortcuts - - - - Unsupported KDF type, cannot decrypt json file - + Scorciatoie Unknown passkeys error - + Errore sconosciuto per le passkeys + + + Invalid KDF iterations, cannot decrypt json file + Numero di iterazioni KDF non valido, impossibile decriptare il file json + + + Unsupported format, ensure your Bitwarden export is password-protected + Formato non supportato, assicurati che l'esportazione Bitwarden sia protetta da password + + + Only PBKDF and Argon2 are supported, cannot decrypt json file + Solo PBKDF e Argon2 sono supportati, non è possibile decriptare il file json + + + Reset Shortcuts + Ripristina scorciatoie + + + Double click an action to change its shortcut + Doppioclicca un'azione per cambiare la sua scorciatoia + + + Filter... + Filtra... + + + Shortcut Conflict + Conflitto scorciatoie + + + Shortcut %1 conflicts with '%2'. Overwrite shortcut? + La scorciatoia %1 è in conflitto con '%2'. Sovrascrivere la scorciatoia? + + + Cannot generate valid passphrases because the wordlist is too short + Impossibile generare passphrase valide perché l'elenco delle parole è troppo corto + + + Encrypted files are not supported. + I file crittografati non sono supportati. + + + Proton Pass Import + Importa Proton Pass + + + Delete plugin data? + Vuoi eliminare i dati del plugin? + + + Delete plugin data from Entry(s)? + Eliminare i dati del plugin dalla voce?Eliminare i dati del plugin dalle voci?Eliminare i dati del plugin dalla/e voce/i? + + + Passkey + Passkey + + + Format to use when exporting. Available choices are 'xml', 'csv' or 'html'. Defaults to 'xml'. + Formato da utilizzare per l'esportazione. Scelte disponibili sono 'xml', 'csv' o 'html'. Predefinito è 'xml'. + + + start minimized to the system tray + avvia minimizzato nell'area di notifica di sistema + + + malformed string, possible unescaped delimiter + stringa non valida, possibile delimitatore senza escape + + + missing closing delimiter + delimitatore di chiusura mancante + + + %1, row: %2, column: %3 + %1, riga: %2, colonna: %3 + + + Tags + Etichette @@ -8708,6 +9271,37 @@ This option is deprecated, use --set-key-file instead. Errore interno di zlib: + + RemoteHandler + + Command `%1` did not finish in time. Process was killed. + Il comando `%1` non ha terminato nei tempi previsti. Il processo è stato ucciso. + + + Failed to upload merged database. Command `%1` did not finish in time. Process was killed. + Upload del database combinato fallito. Il comando `%1` non ha terminato nei tempi previsti. Il processo è stato ucciso. + + + Invalid download parameters provided. + Parametri di download forniti non validi. + + + Command `%1` failed to download database. + Il comando `%1` ha fallito il download del database. + + + Invalid database pointer or upload parameters provided. + Fornito puntatore al database/parametri di upload non corretto. + + + Command `%1` exited with status code: %2 + Il comando `%1` è terminato con status code: %2 + + + Failed to upload merged database. Command `%1` exited with status code: %2 + Upload del database combinato fallito. Il comando `%1` è terminato con status code: %2 + + ReportsWidgetBrowserStatistics @@ -8774,6 +9368,10 @@ This option is deprecated, use --set-key-file instead. Exclude from reports Escludi dal rapporto + + Expire Entry(s)… + Scadenza voce…Scadenza voci…Scadenza voce(i)… + Only show entries that have a URL Mostra solo voci che hanno un URL @@ -8790,36 +9388,33 @@ This option is deprecated, use --set-key-file instead. (Expired) (scaduta) + + Delete plugin data from Entry(s)… + Eliminare i dati del plugin dalla voce...Eliminare i dati del plugin dalle voci...Eliminare i dati del plugin dalla(e) voce(i)... + ReportsWidgetHealthcheck - Hover over reason to show additional details. Double-click entries to edit. - Per visualizzzare dettagli aggiuntivi sposta il cursore sulla notifica. Doppio clic per modificare le voci. + Show expired entries + Mostra voci scadute - Bad - Password quality - Scadente + (Expired) + (scaduta) + + + Hover over reason to show additional details. Double-click entries to edit. + Per visualizzzare dettagli aggiuntivi sposta il cursore sulla notifica. Doppio clic per modificare le voci. Bad — password must be changed Scadente: la password deve essere modificata - - Poor - Password quality - Debole - Poor — password should be changed Inefficace — la password dovrebbe essere modificata - - Weak - Password quality - Intermedia - Weak — consider changing the password Debole — considera di modificare la password @@ -8868,18 +9463,14 @@ This option is deprecated, use --set-key-file instead. Exclude from reports Escludi dal rapporto - - Show expired entries - Mostra voci scadute + + Expire Entry(s)… + Scadenza voce…Scadenza voci…Scadenza voce(i)… Show entries that have been excluded from reports Mostra voci che sono state escluse dai rapporti - - (Expired) - (scaduta) - ReportsWidgetHibp @@ -8976,6 +9567,10 @@ La funzionalità di rete è richiesta per verificare la password con i database Exclude from reports Escludi dal rapporto + + Expire Entry(s)… + Scadenza voce…Scadenza voci…Scadenza voce(i)… + ReportsWidgetPasskeys @@ -9033,15 +9628,15 @@ La funzionalità di rete è richiesta per verificare la password con i database The passkey file will be vulnerable to theft and unauthorized use, if left unsecured. Are you sure you want to continue? - + Il file della passkey sarà esposto a furto oppure uso non autorizzato se lasciato insicuro. Sei sicuro di voler continuare? Please wait, list of entries with passkeys is being updated… - + Attendi, la lista delle voci con passkey è in aggiornamento... No entries with passkeys. - + Nessuna voce con passkeys. @@ -9217,6 +9812,14 @@ La funzionalità di rete è richiesta per verificare la password con i database No agent running, cannot list identities. Nessun agente in esecuzione, impossibile elencare le identità. + + Failed to remove all SSH identities from agent. + Rimozione delle identità SSH dall'agent non riuscite. + + + All SSH identities removed from agent. + Tutte le identità SSH rimosse dall'agent. + SearchHelpWidget @@ -9391,11 +9994,11 @@ La funzionalità di rete è richiesta per verificare la password con i database <html><head/><body><p>This setting does not override disabling recycle bin prompts </p></body></html> - + <html><head/><body><p>Questa impostazione non ha la precedenza sulla disabilitazione dei messaggi del cestino</p></body></html> <html><head/><body><p>This improves compatibility with certain applications which search for password without unlocking the database first.</p><p>But enabling this may also crash the client if the database can not be unlocked within a certain timeout. (Usually 25s, but may be a different value set in applications.) </p></body></html> - + <html><head/><body><p> Questo migliora la compatibilità con alcune applicazioni che cercano la password senza prima sbloccare il database.</p><p>Tuttavia, abilitarlo potrebbe anche mandare in crash il client se il database non può essere sbloccato entro un certo timeout. (di solito 25s, ma potrebbe essere un valore diverso impostato nelle applicazioni.)</p></body></html> @@ -9502,29 +10105,6 @@ La funzionalità di rete è richiesta per verificare la password con i database Esporta in %1 - - ShortcutSettingsWidget - - Double click an action to change its shortcut - - - - Shortcut Conflict - Conflitto scorciatoie - - - Filter... - Filtra... - - - Shortcut %1 conflicts with '%2'. Overwrite shortcut? - - - - Reset Shortcuts - Ripristina scorciatoie - - TagModel @@ -9813,14 +10393,18 @@ Esempio: JBSWY3DPEHPK3PXP No hardware keys detected Nessuna chiave hardware rilevata - - <p>If you own a <a href="https://www.yubico.com/">YubiKey</a> or <a href="https://onlykey.io">OnlyKey</a>, you can use it for additional security.</p><p>The key requires one of its slots to be programmed as <a href="https://docs.yubico.com/yesdk/users-manual/application-otp/challenge-response.html">HMAC-SHA1 Challenge-Response</a>.</p> - - Refresh hardware keys Aggiorna tasti hardware + + <p>If you own a <a href="https://www.yubico.com/">YubiKey</a> or <a href="https://onlykey.io">OnlyKey</a>, you can use it for additional security.</p><p>The key requires one of its slots to be programmed with <a href="https://keepassxc.org/docs/#faq-yubikey-howto">Challenge-Response</a>.</p> + <p>Se possiedi una <a href="https://www.yubico.com/">YubiKey</a> o <a href="https://onlykey.io">OnlyKey</a>, puoi usarla per una maggiore sicurezza.</p><p>La chiave richiede che uno dei suoi slot sia programmato con <a href="https://keepassxc.org/docs/#faq-yubikey-howto">Challenge-Response</a>.</p> + + + Hardware keys found, but no slots are configured + Chiave hardware trovata, ma non è configurato nessuno slot + YubiKeyInterfacePCSC diff --git a/share/translations/keepassxc_ja.ts b/share/translations/keepassxc_ja.ts index 426246479..5712c65c1 100644 --- a/share/translations/keepassxc_ja.ts +++ b/share/translations/keepassxc_ja.ts @@ -98,7 +98,7 @@ Allow All && &Future - 今後も含めすべて許可する + 今後も含めすべて許可する(&F) @@ -217,18 +217,50 @@ You must restart the application to set the new language. Would you like to restart now? 新しい言語を設定するには、このアプリケーションを再起動する必要があります。今すぐ再起動しますか? - - Reset Settings? - 設定をリセットしますか? - - - Are you sure you want to reset all general and security settings to default? - 本当に、すべての全般設定とセキュリティ設定を初期設定に戻しますか? - Select backup storage directory バックアップディレクトリーを選択 + + Confirm Reset + 初期化の確認 + + + Are you sure you want to reset all settings to default? + 本当に、すべての設定を初期設定に戻しますか? + + + Import KeePassXC Settings + KeePassXCの設定をインポート + + + Failed to import settings from %1, not a valid settings file. + データベースファイル %1 を開くのに失敗しました: 有効な設定ファイルではありません。 + + + Export KeePassXC Settings + KeePassXCの設定をエキスパート + + + Small + + + + Normal + 通常 + + + Medium + + + + Large + + + + Custom + カスタム + ApplicationSettingsWidgetGeneral @@ -262,7 +294,7 @@ recent files - 最近使用したファイル + 件の最近使用したファイル Load previously open databases on startup @@ -280,25 +312,6 @@ Include beta releases when checking for updates ベータ版も確認対象にする - - On database unlock, show entries that - 次のエントリーをデータベースのロック解除時に表示する - - - have expired - On database unlock, show entries that... - 有効期限切れ - - - days - On database unlock, show entries that will expire within %1 days - - - - will expire within - On database unlock, show entries that... - 期限切れまであと - File Management ファイル管理 @@ -323,22 +336,10 @@ Backup database file before saving 保存する前にデータベースファイルをバックアップする - - Backup destination - バックアップ先 - - - Specifies the database backup file location. Occurrences of "{DB_FILENAME}" are replaced with the filename of the saved database without extension. {TIME:<format>} is replaced with the backup time, see https://doc.qt.io/qt-5/qdatetime.html#toString. <format> defaults to format string "dd_MM_yyyy_hh-mm-ss". - データベースのバックアップファイルの場所を指定してください。"{DB_FILENAME}" は保存されたデータベースのファイル名から拡張子を取り除いたものに置き換えられます。{TIME:<format>} はバックアップした時刻に置き換えられます。https://doc.qt.io/qt-5/qdatetime.html#toString を確認してください。<format> 既定のフォーマットは "dd_MM_yyyy_hh-mm-ss" です。 - {DB_FILENAME}.old.kdbx {DB_FILENAME}.old.kdbx - - Choose... - 選択... - Use alternative saving method (may solve problems with Dropbox, Google Drive, GVFS, etc.) 別の保存方法を使用する (Dropbox、Google Drive、GVFS などで生じる問題が解決する可能性があります) @@ -505,6 +506,71 @@ Remember last typed entry for: 最後に入力したエントリーの記憶: + + On database unlock, show entries that will expire within + データベースをロック解除した後、次の期間に期限を迎えるエントリーを表示する + + + On database unlock, show entries that will expire within + データベースをロック解除した後、次の期間に期限を迎えるエントリーを表示する + + + days + number of days warning for password expiration + + + + Destination format: + 出力形式: + + + <html><head/><body><p><span style=" font-weight:600;">{DB_FILENAME}</span> is replaced with the filename of the saved database without extension</p><p><span style=" font-weight:600;">{TIME:&lt;format&gt;}</span> is replaced with the specified time format (default: dd_MM_yyyy_hh-mm-ss)</p><p>See the User Guide for more details</p></body></html> + <html><head/><body><p><span style=" font-weight:600;">{DB_FILENAME}</span> は保存したデータベースの拡張子を含まないファイル名で置き換えられます。</p><p><span style=" font-weight:600;">{TIME:&lt;format&gt;}</span> は、時間 (デフォルトでは: dd_MM_yyyy_hh-mm-ss) で置き換えられます。</p><p>詳細はユーザーガイドを確認してください。</p></body></html> + + + Choose folder... + フォルダを選択… + + + Show confirmation before moving entries to recycle bin + エントリーをゴミ箱に移動する前に確認を表示する + + + Copy data on double clicking field in entry view + エントリー表示でフィールドをダブルクリックしてデータをコピーする + + + Show toolbar + ツールバーを表示 + + + Show the menu bar by pressing the Alt key + Alt キーでメニューバーを表示 + + + Show menubar + メニューバーを表示 + + + Import settings… + 設定をインポート… + + + Export settings… + 設定をエキスパート… + + + Open browser on double clicking URL field in entry view + エントリー表示で URL フィールドをダブルクリックしてブラウザーを開く + + + Font size: + フォントサイズ: + + + Font size selection + フォントサイズの選択 + ApplicationSettingsWidgetSecurity @@ -570,18 +636,6 @@ Hide passwords in the entry preview panel エントリーのプレビューパネルのパスワードを非表示にする - - Hide entry notes by default - エントリーのメモを既定で非表示にする - - - Move entries to recycle bin without confirmation - 確認なしでエントリーをゴミ箱に移動する - - - Enable double click to copy the username/password entry columns - ダブルクリックでユーザー名/パスワードエントリーをコピーできるようにする - Privacy プライバシー @@ -594,6 +648,18 @@ Hide TOTP in the entry preview panel エントリーのプレビューパネルで、TOTP を非表示にする + + Lock databases when switching user + ユーザーを切り替えるときにデータベースをロックする + + + Lock Options + ロックのオプション + + + Hide notes in the entry preview panel + エントリーのプレビューパネルのメモを非表示にする + AutoType @@ -641,20 +707,6 @@ Entry does not have attribute for PICKCHARS: %1 エントリーに PICKCHARS の属性がありません: %1 - - Invalid conversion type: %1 - 変換形式が正しくありません: %1 - - - Invalid conversion syntax: %1 - 変換構文が正しくありません: %1 - - - Invalid regular expression syntax %1 -%2 - 正規表現の構文が正しくありません: %1 -%2 - Invalid placeholder: %1 無効なプレースホルダーです: %1 @@ -714,7 +766,7 @@ Trying to send invalid keyboard symbol. - + 無効なキーボード記号を送信しようとしています。 @@ -862,7 +914,7 @@ Please select the correct database for saving credentials. Register new - 今すぐ登録 + 新規登録 Register @@ -874,7 +926,7 @@ Please select the correct database for saving credentials. Relying Party: %1 - 対象サイト (Relying Party): %1 + サービス提供者 (Relying Party): %1 Username: %1 @@ -882,28 +934,29 @@ Please select the correct database for saving credentials. KeePassXC - Passkey credentials - KeePassXC - パスキー認証資格情報 + KeePassXC - パスキー認証情報 Add to existing entry - + 既存のエントリーに追加 Existing passkey found. Do you want to register a new passkey for: - + 既にパスキーが存在しています。 +新しいパスキーを追加しますか: Select the existing passkey and press Update to replace it. - + パスキーを置き換えたい場合、既存のパスキーを選択して更新を押してください。 Authenticate passkey credentials for: - + パスキー認証情報で認証: Do you want to register a passkey for: - + パスキーを登録しますか: @@ -984,20 +1037,21 @@ Do you want to delete the entry? KeePassXC - Passkey credentials - KeePassXC - パスキー認証資格情報 + KeePassXC - パスキー認証情報 Register a new passkey to this entry: - + パスキーを追加するエントリー: KeePassXC - Update passkey - + KeePassXC - パスキーを更新 Entry already has a passkey. Do you want to overwrite the passkey in %1 - %2? - + 既にパスキーがあるエントリーです。 +%1 - %2 のパスキーを上書きしますか? Register @@ -1022,10 +1076,6 @@ Do you want to overwrite the passkey in %1 - %2? General 全般 - - Browsers installed as snaps are currently not supported. - Snap 形式のブラウザーは現在サポートしていません。 - Enable integration for these browsers: これらのブラウザーの統合を有効にする: @@ -1197,18 +1247,6 @@ Do you want to overwrite the passkey in %1 - %2? Custom extension ID カスタム拡張機能 ID - - Due to Snap sandboxing, you must run a script to enable browser integration.<br />You can obtain this script from %1 - Snap によってサンドボックス化されているため、<br />ブラウザー統合を有効にするにはスクリプトを実行する必要があります。<br />スクリプトは次の場所から入手できます: %1 - - - KeePassXC-Browser is needed for the browser integration to work. <br />Download it for %1 and %2 and %3. %4 - ブラウザー統合の動作には KeePassXC-Browser が必要です。<br />KeePassXC-Browser は %1 用、%2 用、%3 用の 3 種類あります。%4 - - - Please see special instructions for browser extension use below - ブラウザー拡張機能を使用するには以下の手順を参照してください - Executable Files 実行ファイル @@ -1251,11 +1289,19 @@ Do you want to overwrite the passkey in %1 - %2? Allows using insecure http://localhost with passkeys for testing purposes. - + 安全ではない http://localhost で、テスト向けにパスキーの使用を許可します。 Allow using localhost with passkeys - + ローカルホストでのパスキーの使用を許可する + + + KeePassXC-Browser is needed for the browser integration to work. <br />Download it for %1 and %2 and %3. + ブラウザー統合の動作には KeePassXC-Browser が必要です。<br />%1 用、%2 用、%3 用からダウンロードしてください。 + + + Browsers installed using Snap or Flatpak are not supported with exception to Firefox installed using Snap. + Snap または Flatpak からインストールしたブラウザー (Snap 版 Firefox を除く) はサポートされていません。 @@ -1399,6 +1445,20 @@ Do you want to overwrite the passkey in %1 - %2? Imported from CSV file: %1 CSV ファイルからインポートしました: %1 + + No Title Selected + タイトルが選択されていません + + + No title column was selected, entries will be hard to tell apart. +Are you sure you want to import? + タイトル行が選択されておらず、エントリーは区別しにくくなります。 +本当にインポートしますか? + + + Tags + タグ + CsvParserModel @@ -1462,6 +1522,14 @@ Backup database located at %2 Recycle Bin ゴミ箱 + + Database file read error. + データベースの読み取りエラーです。 + + + No file path was provided. + ファイルのパスが選択されていません。 + DatabaseOpenDialog @@ -1514,7 +1582,7 @@ Backup database located at %2 Please present or touch your YubiKey to continue… - YubiKey にタッチして続行、または YubiKey を正しく設定してください… + YubiKey を挿入またはタッチして続行します… Database Version Mismatch @@ -1609,14 +1677,6 @@ To prevent this error from appearing, you must go to "Database Settings / S <p>In addition to a password, you can use a secret file to enhance the security of your database. This file can be generated in your database's security settings.</p><p>This is <strong>not</strong> your *.kdbx database file!</p> <p>パスワードだけでなくシークレットファイルを使用することで、データベースのセキュリティを向上させることができます。シークレットファイルはデータベースのセキュリティ設定で生成できます。</p><p>これは *.kdbx データベースファイル<strong>ではありません</strong>!</p> - - Click to add a key file. - クリックしてキーファイルを追加します。 - - - <a href="#" style="text-decoration: underline">I have a key file</a> - <a href="#" style="text-decoration: underline">キーファイルがあります</a> - Use hardware key [Serial: %1] ハードウェアキーを使用する [Serial: %1] @@ -1653,6 +1713,18 @@ Are you sure you want to continue with this file?. Refresh Hardware Keys ハードウェアキーを初期化 + + Click to add a key file. + クリックしてキーファイルを追加します。 + + + <a href="#" style="text-decoration: underline">I have a key file</a> + <a href="#" style="text-decoration: underline">キーファイルがあります</a> + + + Hardware keys found, but no slots are configured. + ハードウェアキーが見つかりましたが、スロットが設定されていません。 + DatabaseSettingWidgetMetaData @@ -1687,6 +1759,22 @@ Are you sure you want to continue with this file?. Maintenance メンテナンス + + KeeShare + KeeShare + + + Secret Service Integration + シークレットサービス統合 + + + Remote Sync + リモート同期 + + + Database Settings: %1 + データベースの設定: %1 + DatabaseSettingsWidgetBrowser @@ -1708,11 +1796,11 @@ Are you sure you want to continue with this file?. Stored keys - 保存されたキー + 保存したキー Stored browser keys - 保存されたブラウザーキー + 保存したブラウザーキー Remove selected key @@ -1829,9 +1917,9 @@ This is only necessary if your database is a copy of another and the browser ext WARNING! You have not set a password. Using a database without a password is strongly discouraged! Are you sure you want to continue without a password? - [警告] パスワードを設定していません。パスワードなしでのデータベースの使用は極力避けるべきです。 + 警告!パスワードを設定していません。パスワードなしのデータベースは特に非推奨です! -パスワードなしで続行してもよろしいですか? +本当にパスワードなしで続行しますか? Continue without password @@ -1855,26 +1943,26 @@ Are you sure you want to continue without a password? Weak password - 弱いパスワード - - - You must enter a stronger password to protect your database. - + 脆弱なパスワード This is a weak password! For better protection of your secrets, you should choose a stronger password. - + 脆弱なパスワードです! 秘密をより最適に保護するために、強固なパスワードを選択することを強くお勧めします。 + + + The provided password does not meet the minimum quality requirement. + 入力されたパスワードが品質要件の最低基準に達していません。 DatabaseSettingsWidgetEncryption Decryption Time: - 復号化時間: + 復号時間: Decryption time in seconds - 復号化時間 (秒) + 復号時間 (秒) Higher values offer more protection, but opening the database will take longer. @@ -2114,13 +2202,12 @@ the oldest history items of an entry will be removed such that only the specified amount of entries remain at most. この設定を保存するか、設定以降に -エントリーを編集すると、 -履歴が古い順に削除され、 -指定した数だけ残るようになります。 +エントリーを編集すると、指定した件数の +範囲内になるまで履歴を古い順に削除します。 Limit the amount of history items per entry to: - 各エントリーの履歴の数を制限する: + 各エントリーの履歴件数を制限する: When saving this setting or editing an entry @@ -2141,19 +2228,22 @@ add up to the specified amount at most. instead of deleting them from the database. Entries deleted from the recycle bin are removed from the database. - + エントリーをデータベースから削除せず +ゴミ箱グループに移動させます。 +ゴミ箱からエントリーを削除すると +データベースから完全に削除されます。 Autosave delay since last change - + 最終更新後、自動保存までの遅延時間 Autosave delay - + 自動保存までの遅延時間 Autosave delay since last change in minutes - + 最終更新後、自動保存までの遅延時間 (分) min @@ -2161,7 +2251,51 @@ removed from the database. Autosave delay since last change checkbox - + 最終更新後、自動保存を遅延させるチェックボックス + + + Public Database Metadata + データベースの公開メタデータ + + + Warning: the following settings are not encrypted. + 警告: 以下の設定は暗号化されません。 + + + Display name: + 表示名: + + + Publically visible display name used on the unlock dialog + ロック解除ダイアログで使用される公開表示の表示名 + + + Database public display name + データベースの公開表示名 + + + Display color: + 表示色: + + + Publically visible color used on the unlock dialog + ロック解除ダイアログで使用される公開表示の表示色 + + + Database public display color chooser + データベースの公開表示色の選択ツール + + + Clear + 消去 + + + Display icon: + 表示アイコン: + + + Select Database Icon + データベースのアイコンを選択 @@ -2258,6 +2392,140 @@ removed from the database. データベースの概要フィールド + + DatabaseSettingsWidgetRemote + + Sync Commands + 同期コマンド + + + Remove + 削除 + + + Command Settings + コマンド設定 + + + Name + 名前 + + + Save + 保存 + + + Download + ダウンロード + + + Command: + コマンド: + + + Download command field + ダウンロードコマンドフィールド + + + e.g.: "sftp user@hostname" or "scp user@hostname:DatabaseOnRemote.kdbx {TEMP_DATABASE}" + 例: "sftp ユーザー名@ホスト名" または "scp ユーザー名@ホスト名:リモートのデータベース.kdbx {TEMP_DATABASE}" + + + Input: + 入力: + + + Download input field + ダウンロード入力フィールド + + + Upload + アップロード + + + Upload command field + アップロードコマンドフィールド + + + e.g.: "sftp user@hostname" or "scp {TEMP_DATABASE} user@hostname:DatabaseOnRemote.kdbx" + 例: "sftp ユーザー名@ホスト名" または "scp {TEMP_DATABASE}ユーザー名@ホスト名:リモートのデータベース.kdbx " + + + Upload input field + アップロード入力フィールド + + + Name cannot be empty. + 名前は空白にできません。 + + + Test + テスト + + + Download command cannot be empty. + ダウンロードコマンドは空白にできません。 + + + Download failed with error: %1 + ダウンロードは次のエラーで失敗しました: %1 + + + Download finished, but file %1 could not be found. + ダウンロードは完了しましたが、ファイル %1 が見つかりません。 + + + Download successful. + 正常にダウンロードを完了しました。 + + + Save Remote Settings + リモート設定を保存 + + + You have unsaved changes. Do you want to save them? + 未保存の変更があります。保存しますか? + + + e.g.: +get DatabaseOnRemote.kdbx {TEMP_DATABASE} +exit +--- +{TEMP_DATABASE} is used as placeholder to store the database in a temporary location +The command has to exit. In case of `sftp` as last command `exit` has to be sent + + 例: +get リモートのデータベース.kdbx {TEMP_DATABASE} +exit +--- +{TEMP_DATABASE} は一時的なデータベース保存先のプレースホルダーとして使用されます +コマンドは終了しなければなりません。「sftp」の場合、最後にコマンド「exit」が送信されなければなりません。 + + + + e.g.: +put {TEMP_DATABASE} DatabaseOnRemote.kdbx +exit +--- +{TEMP_DATABASE} is used as placeholder to store the database in a temporary location +The command has to exit. In case of `sftp` as last command `exit` has to be sent + + 例: +put {TEMP_DATABASE} リモートのデータベース.kdbx +exit +--- +{TEMP_DATABASE} は一時的なデータベース保存先のプレースホルダーとして使用されます +コマンドは終了しなければなりません。「sftp」の場合、最後にコマンド「exit」が送信されなければなりません。 + + + Timeout: + タイムアウト: + + + seconds + + + DatabaseTabWidget @@ -2324,13 +2592,18 @@ This is definitely a bug, please report it to the developers. You are about to export your database to an unencrypted file. This will leave your passwords and sensitive information vulnerable! Are you sure you want to continue? - データベースを暗号化せずにファイルへエクスポートしようとしています。これはパスワードや機密情報が脆弱な状態に置かれることを意味します。続行してもよろしいですか? + データベースを暗号化されないファイルへエクスポートしようとしています。これにより、パスワードや機密情報が脆弱な状態になります!本当に続行しますか? %1 [Locked] Database tab name modifier %1 [ロック] + + %1 [Temporary] + Database tab name modifier + %1 [一時] + DatabaseWidget @@ -2420,7 +2693,7 @@ This is definitely a bug, please report it to the developers. Enter a unique name or overwrite an existing search from the list: - + 独自の名前を入力するか、リストから検索結果を上書きする Save Search @@ -2432,7 +2705,7 @@ This is definitely a bug, please report it to the developers. You are editing an entry. Discard changes and lock anyway? - エントリーを編集中です。変更を破棄してロックしてもよろしいですか? + エントリーを編集中です。変更を破棄してロックしますか? "%1" was modified. @@ -2454,26 +2727,6 @@ Save changes? File has changed ファイルが変更されました - - The database file has changed. Do you want to load the changes? - データベースファイルが変更されました。変更を読み込みますか? - - - Merge Request - マージリクエスト - - - The database file has changed and you have unsaved changes. -Do you want to merge your changes? - データベースファイルが変更され、保存されていません。 -変更をマージしますか? - - - Could not open the new database file while attempting to autoreload. -Error: %1 - 自動再読み込みしようとした際に、新しいデータベースファイルを開くことができませんでした。 -エラー: %1 - Disable safe saves? 安全な保存を無効にしますか? @@ -2510,7 +2763,7 @@ Disable safe saves and try again? Are you sure you want to permanently delete everything from your recycle bin? - ゴミ箱にある全項目を永久に削除してもよろしいですか? + 本当に、ごみ箱からすべてを永久に削除しますか? Could not find database file: %1 @@ -2525,6 +2778,87 @@ Disable safe saves and try again? Database tab name modifier %1 [新しいデータベース] + + Remote Sync did not contain any download or upload commands. + リモート同期にダウンロードコマンドまたはアップロードコマンドがありません。 + + + Remote sync '%1' completed successfully! + リモート同期「%1」は正常に完了しました! + + + + Remote sync '%1' failed: %2 + リモート同期「%1」に失敗しました: %2 + + + Error while saving database %1: %2 + データベース %1 の保存中にエラーが発生しました: %2 + + + Downloading... + ダウンロード中... + + + Uploading... + アップロード中... + + + Syncing... + 同期中... + + + Remove passkey from entry + エントリーからパスキーを削除する + + + Do you want to remove the passkey from this entry? + 本当にこのエントリーからパスキーを削除しますか? + + + The database file "%1" was modified externally + データベースファイル "%1" は外部で編集されました + + + Do you want to load the changes? + 変更を読み込みますか? + + + Reload database + データベースを再読み込み + + + Reloading database… + データベースを再読み込みしています... + + + Reload canceled + 再読み込みがキャンセルされました + + + Reload successful + 再読み込みしました + + + Reload pending user action… + 再読み込みはユーザーの操作の待機中です... + + + The database file "%1" was modified externally.<br>How would you like to proceed?<br><br>Merge all changes<br>Ignore the changes on disk until save<br>Discard unsaved changes + データベースファイル "%1" は外部で編集されました。<br>どのように続行するか選択してください。<br><br>すべての変更をマージ<br>保存するまでディスク上の変更を無視<br>保存されていない変更を破棄 + + + The database file "%1" was modified externally.<br>How would you like to proceed?<br><br>Merge all changes then save<br>Overwrite the changes on disk<br>Discard unsaved changes + データベースファイル "%1" は外部で編集されました。<br>どのように続行するか選択してください。<br><br>すべての変更をマージして保存<br>ディスク上の変更を上書き<br>保存されていない変更を破棄 + + + Database file overwritten. + データベースファイルが上書きされました。 + + + Database file on disk cannot be unlocked with current credentials.<br>Enter new credentials and/or present hardware key to continue. + ディスク上のデータベースファイルは現在の資格情報ではロック解除できませんでした。<br>続行するには、新しい資格情報の入力またはハードウェアキーの挿入が必要です。 + EditEntryWidget @@ -2558,7 +2892,7 @@ Disable safe saves and try again? Are you sure you want to remove this URL? - この URL を削除してもよろしいですか? + 本当にこの URL を削除しますか? Properties @@ -2576,10 +2910,6 @@ Disable safe saves and try again? n/a N/A - - (encrypted) - (暗号化) - Select private key 秘密鍵を選択 @@ -2652,7 +2982,7 @@ Would you like to correct it? Are you sure you want to remove this attribute? - この属性を削除してもよろしいですか? + 本当にこの属性を削除しますか? Reveal @@ -2682,6 +3012,10 @@ Would you like to correct it? %n year(s) %n 年 + + Failed to decrypt SSH key, ensure password is correct. + SSHキーの複合に失敗しました。パスワードが正しいことを確認してください。 + EditEntryWidgetAdvanced @@ -2853,18 +3187,10 @@ Would you like to correct it? Skip Auto-Submit for this entry このエントリーの自動送信をスキップする - - Only send this setting to the browser for HTTP Auth dialogs. If enabled, normal login forms will not show this entry for selection. - この設定をブラウザーの HTTP 認証ダイアログにのみ送信します。有効になっている場合、このエントリーは通常のログインフォームには表示されません。 - Use this entry only with HTTP Basic Auth このエントリーは HTTP ベーシック認証でのみ使用する - - Do not send this setting to the browser for HTTP Auth dialogs. If enabled, HTTP Auth dialogs will not show this entry for selection. - この設定をブラウザーの HTTP 認証ダイアログに送信しません。有効になっている場合、このエントリーは HTTP 認証ダイアログには表示されません。 - Do not use this entry with HTTP Basic Auth このエントリーは HTTP ベーシック認証で使用しない @@ -2883,11 +3209,19 @@ Would you like to correct it? These settings affect the entry's behaviour with the browser extension. - + これらの設定はブラウザー拡張機能でのエントリーの動作に影響します。 Additional URLs - + 追加 URL + + + Only send this entry to the browser for HTTP Auth dialogs. If enabled, normal login forms will not show this entry for selection. + HTTP 認証ダイアログのみでブラウザーにこのエントリーを送信します。有効にすると、このエントリーは通常のログインフィールドでは選択肢に表示しません。 + + + Do not send this entry to the browser for HTTP Auth dialogs. If enabled, HTTP Auth dialogs will not show this entry for selection. + HTTP 認証ダイアログではブラウザーにこのエントリーを送信しません。有効にすると、HTTP 認証ダイアログでこのエントリーを選択肢に表示しません。 @@ -3009,7 +3343,7 @@ Would you like to correct it? T&ags: - タグ(T): + タグ(A): &Expires: @@ -3093,7 +3427,7 @@ Would you like to correct it? Require user confirmation when this key is used - このキーを使用する際に必ずユーザーに確認する + この鍵を使用するときに必ずユーザーに確認する n/a @@ -3111,6 +3445,10 @@ Would you like to correct it? seconds + + Clear agent + エージェントをクリア + EditGroupWidget @@ -3195,11 +3533,11 @@ Would you like to correct it? Omit WWW subdomain from matching: - WWW サブドメインをマッチングから除外 + WWW サブドメインをマッチングから除外する: Omit WWW subdomain from matching toggle for this and sub groups - + このグループとサブグループで WWW サブドメインをマッチングから除外するかを変更します Restrict matching to given browser key: @@ -3553,6 +3891,24 @@ This may cause the affected plugins to malfunction. %1 - Clone %1 - 複製 + + Passkey + パスキー + + + Invalid conversion type: %1 + 変換形式が正しくありません: %1 + + + Invalid conversion syntax: %1 + 変換構文が正しくありません: %1 + + + Invalid regular expression syntax %1 +%2 + 正規表現の構文が正しくありません: %1 +%2 + EntryAttachments @@ -3561,6 +3917,21 @@ This may cause the affected plugins to malfunction. ファイル "%1" を開けません + + EntryAttachmentsDialog + + Form + フォーム + + + File name + ファイル名 + + + File contents... + ファイルの内容... + + EntryAttachmentsModel @@ -3598,14 +3969,6 @@ This may cause the affected plugins to malfunction. Remove 削除 - - Rename selected attachment - 選択した添付ファイルの名前を変更 - - - Rename - 名前を変更 - Open selected attachment 選択した添付ファイルを開く @@ -3632,7 +3995,7 @@ This may cause the affected plugins to malfunction. Are you sure you want to remove %n attachment(s)? - %n 個の添付ファイルを削除してもよろしいですか? + 本当に添付ファイル %n 個を削除しますか? Save attachments @@ -3646,7 +4009,7 @@ This may cause the affected plugins to malfunction. Are you sure you want to overwrite the existing file "%1" with the attachment? - 既存のファイル "%1" を上書きしてもよろしいですか? + 既存のファイル "%1" を添付ファイルで上書きしますか? Confirm overwrite @@ -3720,6 +4083,18 @@ Would you like to overwrite the existing attachment? 添付ファイル "%1" は既に存在します。 既存の添付ファイルを上書きしますか? + + New + 新規作成 + + + Preview + プレビュー + + + Failed to preview an attachment: Attachment not found + 添付ファイルをプレビューできませんでした: 添付ファイルが見つかりません + EntryAttributesModel @@ -3916,7 +4291,11 @@ Would you like to overwrite the existing attachment? Background Color - + 背景色 + + + Group Path + グループのパス @@ -4011,7 +4390,7 @@ Would you like to overwrite the existing attachment? Double click to copy value - + ダブルクリックすると値をコピーします Enabled @@ -4023,7 +4402,7 @@ Would you like to overwrite the existing attachment? Double click to copy to clipboard - + ダブルクリックすると、クリップボードにコピーします @@ -4034,7 +4413,7 @@ Would you like to overwrite the existing attachment? Duplicate URL - + 重複した URL @@ -4049,7 +4428,7 @@ Would you like to overwrite the existing attachment? Reset to defaults - 規定値に戻す + 既定値に戻す + %1 entry(s)... @@ -4291,7 +4670,7 @@ You can enable the DuckDuckGo website icon service in the security section of th Entry count: %1 - + エントリーカウント: %1 Group @@ -4313,6 +4692,14 @@ You can enable the DuckDuckGo website icon service in the security section of th Url Url + + Could not load key file. + + + + Could not open remote database. Password or key file may be incorrect. + + ImportWizardPageSelect @@ -4346,11 +4733,11 @@ You can enable the DuckDuckGo website icon service in the security section of th No unlocked databases available - + ロック解除された利用可能なデータベースはありません Existing Database: - + 既存のデータベース: Import File: @@ -4398,7 +4785,7 @@ You can enable the DuckDuckGo website icon service in the security section of th Comma Separated Values - + カンマ区切りテキスト (.csv) 1Password Export @@ -4416,6 +4803,44 @@ You can enable the DuckDuckGo website icon service in the security section of th KeePass1 Database KeePass1 データベース + + Proton Pass (.json) + Proton Pass (.json) + + + Proton Pass JSON Export + Proton Pass JSON エクスポート + + + Temporary Database + 一時データベース + + + Command: + コマンド: + + + e.g.: "sftp user@hostname" or "scp user@hostname:DatabaseOnRemote.kdbx {TEMP_DATABASE}" + 例: "sftp ユーザー名@ホスト名" または "scp ユーザー名@ホスト名:リモートのデータベース.kdbx {TEMP_DATABASE}" + + + Input: + 入力: + + + e.g.: +get DatabaseOnRemote.kdbx {TEMP_DATABASE} +exit +--- +{TEMP_DATABASE} is used as placeholder to store the database in a temporary location +The command has to exit. In case of `sftp` as last commend `exit` has to be sent + + + + + Remote Database (.kdbx) + リモートのデータベース (.kdbx) + KMessageWidget @@ -4446,7 +4871,7 @@ You can enable the DuckDuckGo website icon service in the security section of th Invalid credentials were provided, please try again. If this reoccurs, then your database file may be corrupt. 不正な資格情報です。再試行してください。 -これが再発した場合は、データベースファイルが破損している可能性があります。 +これが再発する場合は、データベースファイルが破損している可能性があります。 Header doesn't match hash @@ -4503,7 +4928,7 @@ If this reoccurs, then your database file may be corrupt. Invalid credentials were provided, please try again. If this reoccurs, then your database file may be corrupt. 不正な資格情報です。再試行してください。 -これが再発した場合は、データベースファイルが破損している可能性があります。 +これが再発する場合は、データベースファイルが破損している可能性があります。 (HMAC mismatch) @@ -4914,7 +5339,7 @@ Line %2, column %3 Invalid credentials were provided, please try again. If this reoccurs, then your database file may be corrupt. 不正な資格情報です。再試行してください。 -これが再発した場合は、データベースファイルが破損している可能性があります。 +これが再発する場合は、データベースファイルが破損している可能性があります。 Key transformation failed @@ -5179,7 +5604,7 @@ Message: %2 The chosen key file looks like a password database file. A key file must be a static file that never changes or you will lose access to your database forever. Are you sure you want to continue with this file? 選択したキーファイルはパスワードデータベースファイルだと思われます。キーファイルは絶対に変更されることがない、静的なファイルである必要があります。変更される可能性があるファイルでは、データベースに永久にアクセスできなくなる恐れがあります。 -このファイルで続行してもよろしいですか? +本当にこのファイルで続行しますか? @@ -5501,7 +5926,7 @@ Are you sure you want to continue with this file? Show Menubar - + メニューバーを表示 Show Toolbar @@ -5541,27 +5966,21 @@ Are you sure you want to continue with this file? Don't show again for this version - 今後このバージョンについては表示しない + このバージョンについては今後表示しない WARNING: You are using an unstable build of KeePassXC. There is a high risk of corruption, maintain a backup of your databases. This version is not meant for production use. - 警告: KeePassXC の開発版を使用しています。 -データベース破損の危険性が高いため、バックアップを維持します。 -このバージョンは正式版ではありません。 + 警告: お使いの KeePassXC は不安定版です。 +データベース破損の高いリスクがあるため、必ずバックアップを作成してください。 +このバージョンは使用を想定した製品版ではありません。 NOTE: You are using a pre-release version of KeePassXC. Expect some bugs and minor issues, this version is meant for testing purposes. 備考: KeePassXC のプレリリース版を使用しています。 複数のバグや小さな問題点が残っている可能性があります。これはテスト目的のバージョンです。 - - - WARNING: Your Qt version may cause KeePassXC to crash with an On-Screen Keyboard. -We recommend you use the AppImage available on our downloads page. - 警告: オンスクリーンキーボード使用時に、Qt のバージョンが原因で KeePassXC がクラッシュする可能性があります。 -KeePassXC の配布ページから AppImage をダウンロードして使用することをお勧めします。 No Tags @@ -5569,7 +5988,7 @@ KeePassXC の配布ページから AppImage をダウンロードして使用す Restore Entry(s) - + エントリーを復元 Settings @@ -5601,7 +6020,7 @@ KeePassXC の配布ページから AppImage をダウンロードして使用す Please present or touch your YubiKey to continue… - YubiKey にタッチして続行、または YubiKey を正しく設定してください… + YubiKey を挿入またはタッチして続行します… Restart Application? @@ -5635,13 +6054,17 @@ KeePassXC の配布ページから AppImage をダウンロードして使用す Import Passkey パスキーをインポート + + Remote S&ync… + リモート同期(S)... + Quit Application - + アプリケーションを終了 Open About Dialog - + アプリについてダイアログを開く Open Database @@ -5653,11 +6076,11 @@ KeePassXC の配布ページから AppImage をダウンロードして使用す Merge From Database - + データベースからマージ Create Entry - + エントリーを作成 Edit Entry @@ -5665,11 +6088,11 @@ KeePassXC の配布ページから AppImage をダウンロードして使用す Delete Entry - + エントリーを削除 Create Group - + グループを作成 Edit Group @@ -5677,39 +6100,39 @@ KeePassXC の配布ページから AppImage をダウンロードして使用す Delete Group - + グループを削除 Download All Favicons - + すべてのファビコンをダウンロード Sort Groups A-Z - + グループを A-Z で並べ替え Sort Groups Z-A - + グループを Z-A で並べ替え Save Database As - + データベースを別名で保存 Show Database Security - + データベースのセキュリティを表示 Show Database Reports - + データベースのレポートを表示 Show Database Settings - + データベースの設定を表示 Show Passkeys - + パスキーを表示 Clone Entry @@ -5717,11 +6140,11 @@ KeePassXC の配布ページから AppImage をダウンロードして使用す Move Entry Up - + エントリーを上に移動 Move Entry Down - + エントリーを下に移動 Copy Username @@ -5733,31 +6156,35 @@ KeePassXC の配布ページから AppImage をダウンロードして使用す Show Application Settings - + アプリケーションの設定を表示 Show Password Generator - + パスワードを生成 + + + Remove Passkey From Entry + エントリーからパスキーを削除する Perform Auto-Type: {USERNAME} - + 自動入力を実行: {USERNAME} Perform Auto-Type: {USERNAME}{ENTER} - + 自動入力を実行: {USERNAME}{ENTER} Perform Auto-Type: {PASSWORD} - + 自動入力を実行: {PASSWORD} Perform Auto-Type: {PASSWORD}{ENTER} - + 自動入力を実行: {PASSWORD}{ENTER} Perform Auto-Type: {TOTP} - + 自動入力を実行: {TOTP} Copy Title @@ -5793,95 +6220,123 @@ KeePassXC の配布ページから AppImage をダウンロードして使用す Show TOTP QR Code - + TOTP の QR コードを表示 Set up TOTP - + TOTP をセットアップ Empty Recycle Bin - + ゴミ箱を空にする Open Donation Website - + 寄付ウェブサイトを開く Open Bug Report - + バグレポートを開く Open Online Documentation - + オンラインドキュメントを開く Open Keyboard Shortcuts Guide - + キーボードショートカットガイドを開く Save Database Backup - + データベースのバックアップを保存 SSH Agent: Add Key - + SSH エージェント: 鍵を追加 SSH Agent: Remove Key - + SSH エージェント: 鍵を削除 Toggle Compact Mode - + コンパクトモードを切り替え Set Theme: Automatic - + テーマ設定: 自動 Set Theme: Light - + テーマ設定: ライト Set Theme: Dark - + テーマ設定: ダーク Set Theme: Classic - + テーマ設定: クラシック Toggle Show Menubar - + メニューバーの表示を切り替え Toggle Show Toolbar - + ツールバーの表示を切り替え Toggle Show Preview Panel - + プレビューパネルの表示を切り替え Toggle Always on Top - + 常に最前面に表示設定を切り替え Toggle Hide Usernames - + ユーザー名の非表示を切り替え Toggle Hide Passwords - + パスワードの非表示を切り替え Export to XML - + XML にエクスポート Toggle Allow Screen Capture - + スクリーンキャプチャーの許可を切り替え + + + Show Group Panel + グループパネルを表示 + + + Toggle Show Group Panel + グループパネルの表示を切り替え + + + Setup Remote Sync… + リモート同期をセットアップ... + + + Password Generator + パスワード生成 + + + E&xpire Entry… + エントリーを有効期限切れにする(&X)… + + + Clear SSH Agent + SSH エージェントをクリア + + + Clear all identities in ssh-agent + SSH エージェントのすべての ID をクリア @@ -6033,6 +6488,25 @@ KeePassXC の配布ページから AppImage をダウンロードして使用す 新しいデータベースの名前と、必要な場合は説明文を入力してください: + + NewEntryAttachmentsDialog + + Attachment name cannot be empty + 添付ファイルのファイル名は空白にできません + + + Attachment with the same name already exists + 同じファイル名の添付ファイルが既に存在します + + + Save attachment + 添付ファイルを保存 + + + New entry attachment + エントリーの新しい添付ファイル + + NixUtils @@ -6178,11 +6652,11 @@ KeePassXC の配布ページから AppImage をダウンロードして使用す Decryption failed: %1 - 復号化に失敗しました: %1 + 復号に失敗しました: %1 Decryption failed, wrong passphrase? - 復号化に失敗しました。パスフレーズが間違っていませんか? + 復号に失敗しました。パスフレーズが間違っていませんか? Unexpected EOF while reading key @@ -6220,6 +6694,10 @@ KeePassXC の配布ページから AppImage をダウンロードして使用す Unexpected EOF when writing private key 秘密鍵の書き込み時に予期しない EOF がありました + + (encrypted) + (暗号化) + OpenSSHKeyGenDialog @@ -6233,7 +6711,7 @@ KeePassXC の配布ページから AppImage をダウンロードして使用す Bits - + ビット Comment @@ -6268,7 +6746,7 @@ KeePassXC の配布ページから AppImage をダウンロードして使用す Export the following passkey entries. - + 次のパスキーをエクスポートします。 @@ -6338,19 +6816,19 @@ Do you want to overwrite it? Relying Party: %1 - 対象サイト (Relying Party): %1 + サービス提供者 (Relying Party): %1 Import the following passkey: - + 次のパスキーをインポートします: Import the following passkey to this entry: - + このエントリーに次のパスキーをインポートします: Default passkeys group (Imported Passkeys) - + デフォルトのパスキーグループ (Imported Passkeys) @@ -6373,25 +6851,27 @@ Do you want to overwrite it? Open passkey file - + パスキーファイルを開く Cannot import passkey - + パスキーをインポートできません Cannot import passkey file "%1". Data is missing. - + パスキーファイル「%1」をインポートできません。データが存在しません。 Cannot import passkey file "%1". The following data is missing: %2 - + パスキーファイル「%1」をインポートできません。 +次のデータが存在しません: +%2 Cannot import passkey file "%1". Private key is missing or malformed. - + パスキーファイル「%1」をインポートできません。秘密鍵が存在しないか形式に問題があります。 @@ -6572,17 +7052,13 @@ The following data is missing: Also choose from: 次からも選択: - - Excluded characters: "0", "1", "l", "I", "O", "|", "﹒" - 除外される文字: "0"、"1"、"l"、"I"、"O"、"|"、"﹒" - Exclude look-alike characters よく似た文字を除外する Pick characters from every group - すべてする全ての文字種から文字を選ぶ + 選択したすべての文字種から文字を選ぶ Passphrase @@ -6600,10 +7076,6 @@ The following data is missing: Word Count: 単語数: - - Character Count: - 文字数: - Word Case: 単語の大小文字: @@ -6616,10 +7088,6 @@ The following data is missing: Add custom wordlist カスタム単語リストを追加 - - character - 文字 - Close 閉じる @@ -6663,17 +7131,17 @@ The following data is missing: Poor Password quality - 貧弱 + 非常に脆弱 Weak Password quality - 弱い + 脆弱 Good Password quality - 良い + 良好 Excellent @@ -6726,6 +7194,22 @@ Do you want to overwrite it? Special Characters 特殊文字 + + passwordLength + + + + Characters: %1 + 文字: %1 + + + MIXED case + 大文字小文字混在 + + + Excluded characters: "0", "1", "l", "I", "O", "|", "﹒", "B", "8", "G", "6" + 除外される文字: "0", "1", "l", "I", "O", "|", "﹒", "B", "8", "G", "6" + PasswordWidget @@ -6756,17 +7240,17 @@ Do you want to overwrite it? Poor Password quality - 貧弱 + 非常に脆弱 Weak Password quality - 弱い + 脆弱 Good Password quality - 良い + 良好 Excellent @@ -6793,6 +7277,21 @@ Do you want to overwrite it? 文字間で Tab を押す(&T) + + PreviewEntryAttachmentsDialog + + Preview entry attachment + エントリーの添付ファイルをプレビュー + + + No preview available + プレビューできません + + + Image format not supported + 対応していない画像形式です + + QMessageBox @@ -6833,7 +7332,7 @@ Do you want to overwrite it? Continue with weak password - + 脆弱なパスワードで続行 @@ -7142,8 +7641,7 @@ Do you want to overwrite it? Timeout before clearing the clipboard (default is %1 seconds, set to 0 for unlimited). - クリップボードを消去するまでの待ち時間 (規定は %1 秒 -で 0 にすると無制限)。 + クリップボードを消去するまでの待機時間 (既定値は %1 秒、0 にすると無制限)。 Invalid timeout value %1. @@ -7299,27 +7797,27 @@ Do you want to overwrite it? Unset the password for the database. - + データベースのパスワードの設定を解除する。 Unset the key file for the database. - + データベースのキーファイルの設定を解除する。 Edit a database. - + データベースを編集。 Cannot use %1 and %2 at the same time. - + %1 と %2 は同時に使用できません。 Could not change the database key. - + データベース鍵を変更できません。 Database was not modified. - + データベースは変更されていません。 Writing the database failed: %1 @@ -7327,27 +7825,27 @@ Do you want to overwrite it? Successfully edited the database. - + 正常にデータベースを編集しました。 Cannot remove password: The database does not have a password. - + パスワードは削除できません: データベースにパスワードがありません。 Cannot remove file key: The database does not have a file key. - + キーファイルは削除できません: データベースにキーファイルがありません。 Loading the new key file failed: %1 - + 新しいキーファイルの読み込みに失敗しました: %1 Found unexpected Key type %1 - + 想定されていない鍵の形式が見つかりました %1 Cannot remove all the keys from a database. - + パスキーをデータベースから削除できません。 Show a database's information. @@ -7472,10 +7970,6 @@ Do you want to overwrite it? Invalid word count %1 単語数 %1 は不正です - - The word list is too small (< 1000 items) - 単語リストが小さすぎます (< 1000 アイテム) - Title for the entry. エントリーのタイトル。 @@ -7620,10 +8114,6 @@ Do you want to overwrite it? Exit interactive mode. 対話モードを終了する。 - - Format to use when exporting. Available choices are 'xml' or 'csv'. Defaults to 'xml'. - エクスポート時に使用するフォーマット。'xml' が既定で、'csv' も選択可能です。 - Exports the content of a database to standard output in the specified format. データベースの内容を指定した形式で標準出力にエクスポートする。 @@ -7898,7 +8388,7 @@ Available commands: Show all the attributes of the entry. - + エントリーの属性を表示する。 Show the attachments of the entry. @@ -7972,7 +8462,7 @@ Please consider generating a new key file. Please present or touch your YubiKey to continue. - + YubiKey を挿入またはタッチして続行します。 Enter password to encrypt database (optional): @@ -8030,7 +8520,7 @@ Please consider generating a new key file. Very weak password - 非常に弱いパスワード + 非常に脆弱なパスワード Password entropy is %1 bits @@ -8038,7 +8528,7 @@ Please consider generating a new key file. Weak password - 弱いパスワード + 脆弱なパスワード Used in %1/%2 @@ -8212,18 +8702,6 @@ CPU アーキテクチャー: %2 file empty ファイルが空です - - malformed string - 不正な形式の文字列 - - - missing closing quote - 閉じ引用符がありません - - - %1: (row, col) %2,%3 - %1: (行, 列) %2,%3 - AES 256-bit AES 256 ビット @@ -8412,7 +8890,7 @@ CPU アーキテクチャー: %2 KeePassXC is not running. No open database to lock - + KeePassXC が実行されていません。ロックできるデータベースがありません Fatal error while testing the cryptographic functions. @@ -8450,15 +8928,15 @@ CPU アーキテクチャー: %2 Invalid Cipher - + 無効な暗号です Invalid KDF - + 無効な KDF です Access to all entries is denied - + すべてのエントリーへのアクセスが拒否されました allow screenshots and app recording (Windows/macOS) @@ -8467,35 +8945,36 @@ CPU アーキテクチャー: %2 Set the key file for the database. This option is deprecated, use --set-key-file instead. - + データベースにキーファイルを設定します。 +このオプションは非推奨です。--set-key-file の使用を検討してください。 Databases have been locked. - + データベースがロックされました。 Attestation not supported - + 対応していない認証です Credential is excluded - + 資格情報が有効期限切れです Passkeys request canceled - + パスキー要求がキャンセルされました Invalid user verification - + 不正なユーザー認証 Empty public key - + 公開鍵が空白です Invalid URL provided - + 無効な URL が提供されました Passkeys @@ -8559,19 +9038,19 @@ This option is deprecated, use --set-key-file instead. Origin is empty or not allowed - + オリジンが空白または許可されていません Effective domain is not a valid domain - + Effective domain が有効なドメインではありません Origin and RP ID do not match - + オリジンと RP ID が一致しません No supported algorithms were provided - + 対応するアルゴリズムが提供されませんでした Wait for timer to expire @@ -8579,24 +9058,24 @@ This option is deprecated, use --set-key-file instead. Challenge is shorter than required minimum length - + チャレンジが最低文字数より短いです user.id does not match the required length - + user.id の文字数が規定に適合しません Favorite Tag for favorite entries - + お気に入り File does not exist. - + ファイルが存在しません。 Cannot open file: %1 - + ファイルを開けません: %1 Cannot parse file: %1 at position %2 @@ -8604,7 +9083,7 @@ This option is deprecated, use --set-key-file instead. Failed to decrypt json file: %1 - + json ファイルの復号化に失敗しました: %1 Invalid encKeyValidation field @@ -8616,7 +9095,7 @@ This option is deprecated, use --set-key-file instead. Wrong password - + パスワードが間違っています Invalid encrypted data field @@ -8628,11 +9107,11 @@ This option is deprecated, use --set-key-file instead. Cannot initialize cipher - + 暗号を初期化できませんでした Cannot decrypt data - + データを復号できません Bitwarden Import @@ -8641,15 +9120,15 @@ This option is deprecated, use --set-key-file instead. Archived Tag for archived entries - + アーカイブ Invalid 1PUX file format: Not a valid ZIP file. - + 無効な 1PUX ファイル形式: 有効な ZIP ファイルではありません。 Invalid 1PUX file format: Missing export.data - + 無効な 1PUX ファイル形式: export.data が見つかりません。 1Password Import @@ -8657,24 +9136,100 @@ This option is deprecated, use --set-key-file instead. Enter Shortcut - + ショートカットを入力 Action - + アクション Shortcuts - - - - Unsupported KDF type, cannot decrypt json file - + ショートカット Unknown passkeys error + 不明なパスキーエラーが発生しました + + + Invalid KDF iterations, cannot decrypt json file + 無効な KDF 反復、json ファイルを複合できませんでした + + + Unsupported format, ensure your Bitwarden export is password-protected + 対応していないフォーマットです。Bitwarden エクスポートがパスワードで保護されているか確認してください + + + Only PBKDF and Argon2 are supported, cannot decrypt json file + PBKDF と Argon2 に対応しており、json ファイルは復号できません + + + Reset Shortcuts + ショートカットをリセット + + + Double click an action to change its shortcut + ショートカットを変更したいアクションをダブルクリック + + + Filter... + フィルター... + + + Shortcut Conflict + ショートカット重複 + + + Shortcut %1 conflicts with '%2'. Overwrite shortcut? + ショートカット %1 は「%2」と重複しています。上書きしますか? + + + Cannot generate valid passphrases because the wordlist is too short + 単語リストが短すぎるため、有効なパスフレーズを生成できませんでした + + + Encrypted files are not supported. + 暗号化されたファイルには対応していません。 + + + Proton Pass Import + Proton Pass Import + + + Delete plugin data? + プラグインデータを削除しますか? + + + Delete plugin data from Entry(s)? + エントリーからプラグインデータを削除しますか? + + + Passkey + パスキー + + + Format to use when exporting. Available choices are 'xml', 'csv' or 'html'. Defaults to 'xml'. + + start minimized to the system tray + + + + malformed string, possible unescaped delimiter + + + + missing closing delimiter + + + + %1, row: %2, column: %3 + + + + Tags + タグ + QtIOCompressor @@ -8710,6 +9265,37 @@ This option is deprecated, use --set-key-file instead. 内部 zlib エラー: + + RemoteHandler + + Command `%1` did not finish in time. Process was killed. + + + + Failed to upload merged database. Command `%1` did not finish in time. Process was killed. + + + + Invalid download parameters provided. + + + + Command `%1` failed to download database. + + + + Invalid database pointer or upload parameters provided. + + + + Command `%1` exited with status code: %2 + + + + Failed to upload merged database. Command `%1` exited with status code: %2 + + + ReportsWidgetBrowserStatistics @@ -8722,7 +9308,7 @@ This option is deprecated, use --set-key-file instead. Entry has no URLs set - + エントリーには URL が設定されていません Allowed URLs @@ -8730,7 +9316,7 @@ This option is deprecated, use --set-key-file instead. Entry has no Browser Integration settings - + エントリーにはブラウザー統合設定がありません Denied URLs @@ -8746,11 +9332,11 @@ This option is deprecated, use --set-key-file instead. Please wait, browser statistics is being calculated… - + ブラウザー統計の生成中です。しばらくお待ちください... No entries with a URL, or none has browser extension settings saved. - + URL が設定されているエントリーが存在しないか、ブラウザー統合の設定が保存されていません。 Title @@ -8776,55 +9362,56 @@ This option is deprecated, use --set-key-file instead. Exclude from reports レポートから除外 + + Expire Entry(s)… + エントリーを有効期限切れにする… + Only show entries that have a URL - + URL が登録されたエントリーのみ表示する Only show entries that have been explicitly allowed or denied - + 明確に許可または拒否されたエントリーのみ表示する Show expired entries - + 期限切れのエントリーを表示する (Expired) (期限切れ) + + Delete plugin data from Entry(s)… + エントリーからプラグインデータを削除... + ReportsWidgetHealthcheck - Hover over reason to show additional details. Double-click entries to edit. - 理由にマウスオーバーすると追加の詳細が表示されます。エントリーをダブルクリックすると編集できます。 + Show expired entries + 期限切れのエントリーを表示する - Bad - Password quality - 悪い + (Expired) + (期限切れ) + + + Hover over reason to show additional details. Double-click entries to edit. + 理由にマウスオーバーすると追加の詳細が表示されます。エントリーをダブルクリックすると編集できます。 Bad — password must be changed 悪い — パスワードを変更する必要があります - - Poor - Password quality - 貧弱 - Poor — password should be changed - 貧弱 — パスワードを変更する必要があります - - - Weak - Password quality - 弱い + 非常に脆弱 — パスワードを変更する必要があります Weak — consider changing the password - 弱い — パスワードの変更を検討してください + 脆弱 — パスワードの変更を検討してください (Excluded) @@ -8870,17 +9457,13 @@ This option is deprecated, use --set-key-file instead. Exclude from reports レポートから除外 - - Show expired entries - + + Expire Entry(s)… + エントリーを有効期限切れにする… Show entries that have been excluded from reports - - - - (Expired) - (期限切れ) + レポートから除外されたエントリーを表示 @@ -8977,6 +9560,10 @@ This option is deprecated, use --set-key-file instead. Exclude from reports レポートから除外 + + Expire Entry(s)… + エントリーを有効期限切れにする… + ReportsWidgetPasskeys @@ -9018,11 +9605,11 @@ This option is deprecated, use --set-key-file instead. Relying Party - 対象サイト (Relying Party) + サービス提供者 (Relying Party) Show expired entries - + 期限切れのエントリーを表示する (Expired) @@ -9034,15 +9621,15 @@ This option is deprecated, use --set-key-file instead. The passkey file will be vulnerable to theft and unauthorized use, if left unsecured. Are you sure you want to continue? - + パスキーファイルを安全でない環境に保存すると、盗難や不正使用の被害を受ける可能性があります。本当に続行しますか? Please wait, list of entries with passkeys is being updated… - + しばらくお待ちください。パスキーを持つエントリーは更新中です... No entries with passkeys. - + パスキーが登録されたエントリーはありません。 @@ -9218,6 +9805,14 @@ This option is deprecated, use --set-key-file instead. No agent running, cannot list identities. エージェントが実行されていないため、ID の一覧を取得できません。 + + Failed to remove all SSH identities from agent. + SSH ID をエージェントから削除できませんでした。 + + + All SSH identities removed from agent. + すべての SSH ID をエージェントから削除しました。 + SearchHelpWidget @@ -9503,29 +10098,6 @@ This option is deprecated, use --set-key-file instead. %1 にエクスポート - - ShortcutSettingsWidget - - Double click an action to change its shortcut - - - - Shortcut Conflict - - - - Filter... - - - - Shortcut %1 conflicts with '%2'. Overwrite shortcut? - - - - Reset Shortcuts - - - TagModel @@ -9542,7 +10114,7 @@ This option is deprecated, use --set-key-file instead. Weak Passwords - 弱いパスワード + 脆弱なパスワード @@ -9674,7 +10246,7 @@ Example: JBSWY3DPEHPK3PXP Are you sure you want to delete TOTP settings for this entry? - このエントリーの TOTP 設定を削除してもよろしいですか? + 本当にこのエントリーの TOTP 設定を削除しますか? @@ -9719,7 +10291,7 @@ Example: JBSWY3DPEHPK3PXP WelcomeWidget Start storing your passwords securely in a KeePassXC database - KeePassXC データベースに安全にパスワードを保管する + KeePassXC データベースで安全なパスワード保管の強化を開始します Recent databases @@ -9814,14 +10386,18 @@ Example: JBSWY3DPEHPK3PXP No hardware keys detected 検出したハードウェアキーはありません - - <p>If you own a <a href="https://www.yubico.com/">YubiKey</a> or <a href="https://onlykey.io">OnlyKey</a>, you can use it for additional security.</p><p>The key requires one of its slots to be programmed as <a href="https://docs.yubico.com/yesdk/users-manual/application-otp/challenge-response.html">HMAC-SHA1 Challenge-Response</a>.</p> - - Refresh hardware keys ハードウェアトークンを初期化 + + <p>If you own a <a href="https://www.yubico.com/">YubiKey</a> or <a href="https://onlykey.io">OnlyKey</a>, you can use it for additional security.</p><p>The key requires one of its slots to be programmed with <a href="https://keepassxc.org/docs/#faq-yubikey-howto">Challenge-Response</a>.</p> + <p><a href="https://www.yubico.com/">YubiKey</a> または <a href="https://onlykey.io">OnlyKey</a> をお持ちの場合、セキュリティをさらに強化できます。</p><p><a href="https://docs.yubico.com/yesdk/users-manual/application-otp/challenge-response.html">チャレンジレスポンス</a>に設定されたスロットが 1 つ必要です。</p> + + + Hardware keys found, but no slots are configured + ハードウェアキーを検出しましたが、スロットが設定されていません + YubiKeyInterfacePCSC @@ -9831,11 +10407,11 @@ Example: JBSWY3DPEHPK3PXP Could not find or access hardware key with serial number %1. Please present it to continue. - シリアルナンバー %1 のハードウェアキーが見つからない、またはアクセスできませんでした。正しく設定して続行してください。 + シリアルナンバー %1 のハードウェアキーが見つからない、またはアクセスできませんでした。続行するには正しく挿入してください。 Hardware key is locked or timed out. Unlock or re-present it to continue. - ハードウェアキーがロックされているか、タイムアウトしました。ロックを解除するか、正しく設定し直してから続行してください。 + ハードウェアキーがロックされているか、タイムアウトしました。続行するにはロック解除または再挿入してください。 Hardware key was not found or is not configured. diff --git a/share/translations/keepassxc_km.ts b/share/translations/keepassxc_km.ts index f90713cb4..cd8dfdf59 100644 --- a/share/translations/keepassxc_km.ts +++ b/share/translations/keepassxc_km.ts @@ -217,18 +217,50 @@ You must restart the application to set the new language. Would you like to restart now? អ្នកត្រូវចាប់ផ្តើមកម្មវិធីឡើងវិញ ដើម្បីកំណត់ភាសាថ្មី។ ចង់ចាប់ផ្តើមឡើងវិញទេ? - - Reset Settings? - កំណត់ឡើងវិញ? - - - Are you sure you want to reset all general and security settings to default? - តើអ្នកប្រាកដទេថាចង់កំណត់ឡើងវិញទូទៅទាំងអស់ និងកំណត់សុវត្ថិភាពទៅជាលំនាំដើមវិញ? - Select backup storage directory ជ្រើសរើសការបម្រុងទុកបញ្ចីផ្ទុក + + Confirm Reset + បញ្ជាក់ការកំណត់ឡើងវិញ + + + Are you sure you want to reset all settings to default? + តើអ្នកប្រាកដទេថាចង់កំណត់ឡើងវិញទាំងអស់ទៅជាលំនាំដើមវិញ? + + + Import KeePassXC Settings + នាំចូលការកំណត់ KeePassXC + + + Failed to import settings from %1, not a valid settings file. + បានបរាជ័យក្នុងការនាំចូលការកំណត់ %1 មិនមែនជាឯកសារកំណត់ត្រឹមត្រូវទេ។ + + + Export KeePassXC Settings + នាំចេញការកំណត់ KeePassXC + + + Small + តូច + + + Normal + ធម្មតា + + + Medium + មធ្យម + + + Large + + + + Custom + + ApplicationSettingsWidgetGeneral @@ -280,25 +312,6 @@ Include beta releases when checking for updates បញ្ចូលការចេញផ្សាយសាកល្បង ពេលឆែករកបច្ចុប្បន្ន - - On database unlock, show entries that - ពេលបើកសោរឃ្លាំងទិន្នន័យ បង្ហាញធាតុដែល - - - have expired - On database unlock, show entries that... - ផុតកំណត់ប្រើហើយ - - - days - On database unlock, show entries that will expire within %1 days - ថ្ងៃ - - - will expire within - On database unlock, show entries that... - នឹងផុតកំណត់ប្រើ ក្នុងរយៈពេល - File Management ការគ្រប់គ្រងឯកសារ @@ -323,22 +336,10 @@ Backup database file before saving បម្រុងទុកឯសារឃ្លាំងទិន្នន័យ មុនពេលរក្សាទុក។ - - Backup destination - គោលដៅបម្រុងទុក - - - Specifies the database backup file location. Occurrences of "{DB_FILENAME}" are replaced with the filename of the saved database without extension. {TIME:<format>} is replaced with the backup time, see https://doc.qt.io/qt-5/qdatetime.html#toString. <format> defaults to format string "dd_MM_yyyy_hh-mm-ss". - បញ្ជាក់ពីទីតាំងឯកសារបម្រុងទុកមូលដ្ឋានទិន្នន័យ។ ការកើតឡើងនៃ "{DB_FILENAME}" ត្រូវបានជំនួសដោយឈ្មោះឯកសារនៃមូលដ្ឋានទិន្នន័យដែលបានរក្សាទុកដោយគ្មានកម្មវិធីបន្ថែម។ {TIME:<format>} ត្រូវបានជំនួសដោយពេលវេលាបម្រុងទុក សូមមើល https://doc.qt.io/qt-5/qdatetime.html#toString. <format> លំនាំដើម ដើម្បីធ្វើទ្រង់ទ្រាយខ្សែអក្សរ "dd_MM_yyyy_hh-mm-ss"។ - {DB_FILENAME}.old.kdbx {DB_FILENAME}.old.kdbx - - Choose... - ជ្រើសរើស... - Use alternative saving method (may solve problems with Dropbox, Google Drive, GVFS, etc.) ប្រើវិធីសន្សំជំនួស (អាចដោះស្រាយបញ្ហាជាមួយ Dropbox, Google Drive, GVFS ជាដើម) @@ -506,6 +507,71 @@ Remember last typed entry for: ចងចាំការបញ្ចូលដោយសរសេរចុងក្រោយសម្រាប់: + + On database unlock, show entries that will expire within + នៅលើការដោះសោមូលដ្ឋានទិន្នន័យ បង្ហាញធាតុដែលនឹងផុតកំណត់នៅក្នុង + + + On database unlock, show entries that will expire within + + + + days + number of days warning for password expiration + ថ្ងៃ + + + Destination format: + + + + <html><head/><body><p><span style=" font-weight:600;">{DB_FILENAME}</span> is replaced with the filename of the saved database without extension</p><p><span style=" font-weight:600;">{TIME:&lt;format&gt;}</span> is replaced with the specified time format (default: dd_MM_yyyy_hh-mm-ss)</p><p>See the User Guide for more details</p></body></html> + + + + Choose folder... + + + + Show confirmation before moving entries to recycle bin + + + + Copy data on double clicking field in entry view + + + + Show toolbar + បង្ហាញរបាឧបករណ៍ + + + Show the menu bar by pressing the Alt key + បង្ហាញរបារឧបករណ៍ដោយចុចគ្រាប់ចុច Alt + + + Show menubar + បង្ហាញរបាឧបករណ៍ + + + Import settings… + នាំចូលការកំណត់… + + + Export settings… + នាំចេញលការកំណត់… + + + Open browser on double clicking URL field in entry view + + + + Font size: + + + + Font size selection + + ApplicationSettingsWidgetSecurity @@ -571,18 +637,6 @@ Hide passwords in the entry preview panel លាក់ពាក្យសម្ងាត់នៅក្នុងផ្ទាំងមើលជាមុន - - Hide entry notes by default - លាក់កំណត់ចំណាំចូលតាមលំនាំដើម - - - Move entries to recycle bin without confirmation - ផ្លាស់ទីធាតុរចូលទៅក្នុងធុងសំរាមដោយគ្មានការបញ្ចាក់ - - - Enable double click to copy the username/password entry columns - បើការចុចពីរដើម្បីចម្លង username/password លើជួរឈរ - Privacy ឯកជនភាព @@ -595,6 +649,18 @@ Hide TOTP in the entry preview panel លាក់ TOTP នៅក្នុងបន្ទះមើលជាមុនធាតុ + + Lock databases when switching user + + + + Lock Options + ជម្រើសចាក់សោ + + + Hide notes in the entry preview panel + + AutoType @@ -642,20 +708,6 @@ Entry does not have attribute for PICKCHARS: %1 ការបញ្ចូលមិនមានលក្ខណៈសម្រាប់ PICKCHARS៖ %1 - - Invalid conversion type: %1 - ការ​បម្លែង​មិន​ត្រឹមត្រូវ៖ %1 - - - Invalid conversion syntax: %1 - វាក្យសម្ព័ន្ធនៃការបំប្លែងមិនត្រឹមត្រូវ៖ %1 - - - Invalid regular expression syntax %1 -%2 - វាក្យសម្ព័ន្ធកន្សោមពាក្យធម្មតាមិនត្រឹមត្រូវ %1 -%2 - Invalid placeholder: %1 កន្លែងរក្សាទុកមិនត្រឹមត្រូវ៖ %1 @@ -1023,10 +1075,6 @@ Do you want to overwrite the passkey in %1 - %2? General ទូទៅ - - Browsers installed as snaps are currently not supported. - កម្មវិធីរុករកតាមអ៊ីនធឺណិតដែលបានដំឡើងជាខ្ទាស់ ថ្មីៗនេះមិនអាចប្រើប្រាស់បានទេ។ - Enable integration for these browsers: បើកការរួមបញ្ចូលសម្រាប់កម្មវិធីរុករកទាំងនេះ៖ @@ -1198,18 +1246,6 @@ Do you want to overwrite the passkey in %1 - %2? Custom extension ID លេខសម្គាល់កម្មវិធីបន្ថែមផ្ទាល់ខ្លួន - - Due to Snap sandboxing, you must run a script to enable browser integration.<br />You can obtain this script from %1 - ដោយសារមុខងារ Snap sandboxing នោះអ្នកត្រូវតែដំណើរការស្គ្រីបដើម្បីបើកការរួមបញ្ចូលកម្មវិធីរុករកតាមអ៊ីនធឺណិត។<br />អ្នកអាចទទួលបានស្គ្រីបនេះមកពី% 1 - - - KeePassXC-Browser is needed for the browser integration to work. <br />Download it for %1 and %2 and %3. %4 - KeePassXC-កម្មវិធីរុករកតាមអ៊ីនធឺណិតត្រូវការសម្រាប់ការរួមបញ្ចូលកម្មវិធីរុករកតាមអ៊ីនធឺណិតនេះដើម្បីធ្វើការ។ <br />ទាញយកវាសម្រាប់ %1 និង %2 និង %3. %4 - - - Please see special instructions for browser extension use below - សូមមើលការណែនាំពិសេសសម្រាប់ការប្រើប្រាស់កម្មវិធីបន្ថែម​របស់កម្មវិធីរុករកតាមអ៊ីនធឺណិតខាងក្រោម - Executable Files ឯកសារដែលអនុវត្តន៍បាន @@ -1259,6 +1295,14 @@ Do you want to overwrite the passkey in %1 - %2? Allow using localhost with passkeys + + KeePassXC-Browser is needed for the browser integration to work. <br />Download it for %1 and %2 and %3. + + + + Browsers installed using Snap or Flatpak are not supported with exception to Firefox installed using Snap. + + CloneDialog @@ -1401,6 +1445,19 @@ Do you want to overwrite the passkey in %1 - %2? Imported from CSV file: %1 + + No Title Selected + + + + No title column was selected, entries will be hard to tell apart. +Are you sure you want to import? + + + + Tags + ស្លាក + CsvParserModel @@ -1464,6 +1521,14 @@ Backup database located at %2 Recycle Bin ធុងសំរាម + + Database file read error. + + + + No file path was provided. + + DatabaseOpenDialog @@ -1609,14 +1674,6 @@ To prevent this error from appearing, you must go to "Database Settings / S <p>In addition to a password, you can use a secret file to enhance the security of your database. This file can be generated in your database's security settings.</p><p>This is <strong>not</strong> your *.kdbx database file!</p> - - Click to add a key file. - - - - <a href="#" style="text-decoration: underline">I have a key file</a> - - Use hardware key [Serial: %1] @@ -1649,6 +1706,18 @@ Are you sure you want to continue with this file?. Refresh Hardware Keys + + Click to add a key file. + + + + <a href="#" style="text-decoration: underline">I have a key file</a> + + + + Hardware keys found, but no slots are configured. + + DatabaseSettingWidgetMetaData @@ -1683,6 +1752,22 @@ Are you sure you want to continue with this file?. Maintenance តំហែទាំ + + KeeShare + KeeShare + + + Secret Service Integration + ការដាក់បញ្ចូលសេវាពាក្យសម្ងាត់ + + + Remote Sync + + + + Database Settings: %1 + + DatabaseSettingsWidgetBrowser @@ -1854,11 +1939,11 @@ Are you sure you want to continue without a password? ពាក្យសម្ងាត់ខ្សោយ - You must enter a stronger password to protect your database. + This is a weak password! For better protection of your secrets, you should choose a stronger password. - This is a weak password! For better protection of your secrets, you should choose a stronger password. + The provided password does not meet the minimum quality requirement. @@ -2162,6 +2247,50 @@ removed from the database. Autosave delay since last change checkbox + + Public Database Metadata + + + + Warning: the following settings are not encrypted. + + + + Display name: + + + + Publically visible display name used on the unlock dialog + + + + Database public display name + ឈ្មោះបង្ហាញសាធារណៈមូលដ្ឋានទិន្នន័យ + + + Display color: + ពណ៌បង្ហាញ៖ + + + Publically visible color used on the unlock dialog + + + + Database public display color chooser + + + + Clear + ជម្រះ + + + Display icon: + + + + Select Database Icon + + DatabaseSettingsWidgetKeeShare @@ -2257,6 +2386,129 @@ removed from the database. កន្លែងបញ្ចូលការពណ៌នាមូលដ្ឋានទិន្នន័យ + + DatabaseSettingsWidgetRemote + + Sync Commands + + + + Remove + ដកចេញ + + + Command Settings + + + + Name + ឈ្មោះ + + + Save + រក្សាទុក + + + Download + + + + Command: + + + + Download command field + + + + e.g.: "sftp user@hostname" or "scp user@hostname:DatabaseOnRemote.kdbx {TEMP_DATABASE}" + + + + Input: + + + + Download input field + + + + Upload + + + + Upload command field + + + + e.g.: "sftp user@hostname" or "scp {TEMP_DATABASE} user@hostname:DatabaseOnRemote.kdbx" + + + + Upload input field + + + + Name cannot be empty. + + + + Test + + + + Download command cannot be empty. + + + + Download failed with error: %1 + + + + Download finished, but file %1 could not be found. + + + + Download successful. + + + + Save Remote Settings + + + + You have unsaved changes. Do you want to save them? + + + + e.g.: +get DatabaseOnRemote.kdbx {TEMP_DATABASE} +exit +--- +{TEMP_DATABASE} is used as placeholder to store the database in a temporary location +The command has to exit. In case of `sftp` as last command `exit` has to be sent + + + + + e.g.: +put {TEMP_DATABASE} DatabaseOnRemote.kdbx +exit +--- +{TEMP_DATABASE} is used as placeholder to store the database in a temporary location +The command has to exit. In case of `sftp` as last command `exit` has to be sent + + + + + Timeout: + + + + seconds + វិនាទី + + DatabaseTabWidget @@ -2330,6 +2582,11 @@ This is definitely a bug, please report it to the developers. Database tab name modifier %1 [បានចាក់សោ] + + %1 [Temporary] + Database tab name modifier + + DatabaseWidget @@ -2453,26 +2710,6 @@ Save changes? File has changed ឯកសារបានផ្លាស់ប្តូរ - - The database file has changed. Do you want to load the changes? - ឯកសារមូលដ្ឋានទិន្នន័យបានផ្លាស់ប្តូររួចហើយ។ តើអ្នកចង់ផ្ទុកការផ្លាស់ប្តូរឬទេ? - - - Merge Request - សំណើដាក់បញ្ចូល - - - The database file has changed and you have unsaved changes. -Do you want to merge your changes? - ឯកសារមូលដ្ឋានទិន្នន័យបានផ្លាស់ប្តូររួចរាល់ និងអ្នកមានការផ្លាស់ប្តូរដែលមិនបានរក្សាទុក។ -តើអ្នកចង់ដាក់បញ្ចូលការផ្លាស់ប្តូររបស់អ្នកឬទេ? - - - Could not open the new database file while attempting to autoreload. -Error: %1 - មិន​អាច​បើក​ឯកសារ​មូលដ្ឋាន​ទិន្នន័យ​ថ្មី នៅពេលកំពុង​ព្យាយាម​ផ្ទុក​ឡើង​វិញ​ដោយ​ស្វ័យប្រវត្តិ។ -បញ្ហា៖% 1 - Disable safe saves? បិទដំណើរការនៃការរក្សាទុកដោយសុវត្ថិភាព? @@ -2524,6 +2761,86 @@ Disable safe saves and try again? Database tab name modifier %1 [ឃ្លាំងទិន្នន័យថ្មី] + + Remote Sync did not contain any download or upload commands. + + + + Remote sync '%1' completed successfully! + + + + Remote sync '%1' failed: %2 + + + + Error while saving database %1: %2 + + + + Downloading... + + + + Uploading... + + + + Syncing... + + + + Remove passkey from entry + + + + Do you want to remove the passkey from this entry? + + + + The database file "%1" was modified externally + + + + Do you want to load the changes? + + + + Reload database + + + + Reloading database… + + + + Reload canceled + + + + Reload successful + + + + Reload pending user action… + + + + The database file "%1" was modified externally.<br>How would you like to proceed?<br><br>Merge all changes<br>Ignore the changes on disk until save<br>Discard unsaved changes + + + + The database file "%1" was modified externally.<br>How would you like to proceed?<br><br>Merge all changes then save<br>Overwrite the changes on disk<br>Discard unsaved changes + + + + Database file overwritten. + + + + Database file on disk cannot be unlocked with current credentials.<br>Enter new credentials and/or present hardware key to continue. + + EditEntryWidget @@ -2575,10 +2892,6 @@ Disable safe saves and try again? n/a គ្មាន - - (encrypted) - (បានអ៊ិនគ្រីប) - Select private key ជ្រើសរើសពាក្យសម្ងាត់ផ្ទាល់ខ្លួន @@ -2681,6 +2994,10 @@ Would you like to correct it? %n year(s) %n ឆ្នាំ + + Failed to decrypt SSH key, ensure password is correct. + + EditEntryWidgetAdvanced @@ -2852,18 +3169,10 @@ Would you like to correct it? Skip Auto-Submit for this entry រំលងការបញ្ជូនដោយស្វ័យប្រវត្តិសម្រាប់ការបញ្ចូលនេះ - - Only send this setting to the browser for HTTP Auth dialogs. If enabled, normal login forms will not show this entry for selection. - ផ្ញើតែការកំណត់នេះទៅកម្មវិធីរុករកតាមអ៊ីនធឺណិតសម្រាប់ប្រអប់ការផ្ទៀងផ្ទាត់ភាពត្រឹមត្រូវ HTTP Auth ប៉ុណ្ណោះ។ ប្រសិនបើបានបើក ទម្រង់ចូលធម្មតានឹងមិនបង្ហាញទិន្នន័យបញ្ចូលនេះឱ្យជ្រើសរើសទេ។ - Use this entry only with HTTP Basic Auth ប្រើប្រាស់ទិន្នន័យបញ្ចូលនេះតែជាមួយ HTTP Basic Auth ប៉ុណ្ណោះ - - Do not send this setting to the browser for HTTP Auth dialogs. If enabled, HTTP Auth dialogs will not show this entry for selection. - សូមកុំផ្ញើការកំណត់នេះទៅកាន់កម្មវិធីរុករកតាមអ៊ីនធឺណិតសម្រាប់ប្រអប់ការផ្ទៀងផ្ទាត់ភាពត្រឹមត្រូវ HTTP Auth។ ប្រសិនបើបានបើកប្រអប់ការផ្ទៀងផ្ទាត់ភាពត្រឹមត្រូវ HTTP Auth នឹងមិនបង្ហាញទិន្នន័យបញ្ចូលនេះសម្រាប់ការជ្រើសរើសទេ។ - Do not use this entry with HTTP Basic Auth កុំប្រើទិន្នន័យបញ្ចូលនេះជាមួយ HTTP Basic Auth @@ -2888,6 +3197,14 @@ Would you like to correct it? Additional URLs + + Only send this entry to the browser for HTTP Auth dialogs. If enabled, normal login forms will not show this entry for selection. + + + + Do not send this entry to the browser for HTTP Auth dialogs. If enabled, HTTP Auth dialogs will not show this entry for selection. + + EditEntryWidgetHistory @@ -3110,6 +3427,10 @@ Would you like to correct it? seconds វិនាទី + + Clear agent + + EditGroupWidget @@ -3552,6 +3873,24 @@ This may cause the affected plugins to malfunction. %1 - Clone %1 - ក្លូន + + Passkey + + + + Invalid conversion type: %1 + ប្រភេទនៃការ​បម្លែង​មិន​ត្រឹមត្រូវ៖ %1 + + + Invalid conversion syntax: %1 + វាក្យសម្ព័ន្ធនៃការបំប្លែងមិនត្រឹមត្រូវ៖ %1 + + + Invalid regular expression syntax %1 +%2 + វាក្យសម្ព័ន្ធកន្សោមពាក្យធម្មតាមិនត្រឹមត្រូវ %1 +%2 + EntryAttachments @@ -3560,6 +3899,21 @@ This may cause the affected plugins to malfunction. មិនអាចបើកឯកសារ "% 1" បានទេ + + EntryAttachmentsDialog + + Form + ទម្រង់ + + + File name + + + + File contents... + + + EntryAttachmentsModel @@ -3597,14 +3951,6 @@ This may cause the affected plugins to malfunction. Remove ដកចេញ - - Rename selected attachment - ប្តូរឈ្មោះឯកសារភ្ជាប់ដែលបានជ្រើសរើស - - - Rename - ប្តូរឈ្មោះ - Open selected attachment បើកឯកសារភ្ជាប់ដែលបានជ្រើសរើស @@ -3715,6 +4061,18 @@ Would you like to overwrite the existing attachment? ឯកសារភ្ជាប់ "% 1" មានស្រាប់ហើយ។ តើអ្នកចង់សរសេរជាន់លើឯកសារភ្ជាប់ដែលមានស្រាប់ឬទេ? + + New + + + + Preview + មើលជាមុន + + + Failed to preview an attachment: Attachment not found + + EntryAttributesModel @@ -3913,6 +4271,10 @@ Would you like to overwrite the existing attachment? Background Color + + Group Path + + EntryPreviewWidget @@ -4308,6 +4670,14 @@ You can enable the DuckDuckGo website icon service in the security section of th Url + + Could not load key file. + + + + Could not open remote database. Password or key file may be incorrect. + + ImportWizardPageSelect @@ -4411,6 +4781,44 @@ You can enable the DuckDuckGo website icon service in the security section of th KeePass1 Database + + Proton Pass (.json) + + + + Proton Pass JSON Export + + + + Temporary Database + + + + Command: + + + + e.g.: "sftp user@hostname" or "scp user@hostname:DatabaseOnRemote.kdbx {TEMP_DATABASE}" + + + + Input: + + + + e.g.: +get DatabaseOnRemote.kdbx {TEMP_DATABASE} +exit +--- +{TEMP_DATABASE} is used as placeholder to store the database in a temporary location +The command has to exit. In case of `sftp` as last commend `exit` has to be sent + + + + + Remote Database (.kdbx) + + KMessageWidget @@ -5549,12 +5957,6 @@ This version is not meant for production use. Expect some bugs and minor issues, this version is meant for testing purposes. ចំណាំ៖ អ្នកកំពុងប្រើប្រាស់កំណែមុនចេញផ្សាយរបស់កម្មវិធី KeePassXC។ កំហុស និងបញ្ហាតូចតាចមួយចំនួននឹងអាចកើតមានឡើង ដោយសារកំណែនេះមានគោលបំណងសម្រាប់ការធ្វើតេស្តតែប៉ុណ្ណោះ។ - - - WARNING: Your Qt version may cause KeePassXC to crash with an On-Screen Keyboard. -We recommend you use the AppImage available on our downloads page. - ការព្រមាន៖ កំណែ Qt របស់អ្នកអាចបណ្តាលឱ្យ KeePassXC គាំងជាមួយនឹងក្តារចុចលើអេក្រង់។ -យើងសូមណែនាំអ្នកឱ្យប្រើប្រាស់ AppImage នេះដែលអាចប្រើប្រាស់បាននៅលើទំព័រទាញយករបស់យើង។ No Tags @@ -5628,6 +6030,10 @@ We recommend you use the AppImage available on our downloads page. Import Passkey + + Remote S&ync… + + Quit Application @@ -5732,6 +6138,10 @@ We recommend you use the AppImage available on our downloads page. Show Password Generator + + Remove Passkey From Entry + + Perform Auto-Type: {USERNAME} @@ -5876,6 +6286,34 @@ We recommend you use the AppImage available on our downloads page. Toggle Allow Screen Capture + + Show Group Panel + + + + Toggle Show Group Panel + + + + Setup Remote Sync… + + + + Password Generator + + + + E&xpire Entry… + + + + Clear SSH Agent + + + + Clear all identities in ssh-agent + + ManageDatabase @@ -6026,6 +6464,25 @@ We recommend you use the AppImage available on our downloads page. សូមបំពេញឈ្មោះដែលបង្ហាញនេះនិងការពណ៌នាជាជម្រើសសម្រាប់មូលដ្ឋានទិន្នន័យថ្មីរបស់អ្នក៖ + + NewEntryAttachmentsDialog + + Attachment name cannot be empty + + + + Attachment with the same name already exists + + + + Save attachment + + + + New entry attachment + + + NixUtils @@ -6213,6 +6670,10 @@ We recommend you use the AppImage available on our downloads page. Unexpected EOF when writing private key EOFដែលមិនបានរំពឹងទុកនៅពេលសរសេរសោគន្លឹះ + + (encrypted) + (បានអ៊ិនគ្រីប) + OpenSSHKeyGenDialog @@ -6563,10 +7024,6 @@ The following data is missing: Also choose from: ក៏អាចជ្រើសរើសពី៖ - - Excluded characters: "0", "1", "l", "I", "O", "|", "﹒" - មិនរាប់បញ្ចូលតួអក្សរ៖ "0", "1", "l", "I", "O", "|", "﹒" - Exclude look-alike characters មិនរាប់បញ្ចូលតួអក្សរដែលមានលក្ខណៈស្រដៀងគ្នា @@ -6591,10 +7048,6 @@ The following data is missing: Word Count: ចំនួនពាក្យ៖ - - Character Count: - ចំនួនតួអក្សរ៖ - Word Case: ពាក្យអក្សរតូច៖ @@ -6607,10 +7060,6 @@ The following data is missing: Add custom wordlist បន្ថែមបញ្ជីពាក្យផ្ទាល់ខ្លួន - - character - តួអក្សរ - Close បិទ @@ -6717,6 +7166,22 @@ Do you want to overwrite it? Special Characters តួអក្សរពិសេស + + passwordLength + + + + Characters: %1 + + + + MIXED case + + + + Excluded characters: "0", "1", "l", "I", "O", "|", "﹒", "B", "8", "G", "6" + + PasswordWidget @@ -6784,6 +7249,21 @@ Do you want to overwrite it? ចុច &ថេបរវាងតួអក្សរ + + PreviewEntryAttachmentsDialog + + Preview entry attachment + + + + No preview available + + + + Image format not supported + + + QMessageBox @@ -7462,10 +7942,6 @@ Do you want to overwrite it? Invalid word count %1 ចំនួន​ពាក្យ​មិន​ត្រឹមត្រូវ %1 - - The word list is too small (< 1000 items) - បញ្ជីពាក្យតូចពេក (< 1000 ធាតុ) - Title for the entry. ចំណងជើងសម្រាប់ការបញ្ចូល។ @@ -7610,10 +8086,6 @@ Do you want to overwrite it? Exit interactive mode. ចេញពីម៉ូដអន្តរកម្ម។ - - Format to use when exporting. Available choices are 'xml' or 'csv'. Defaults to 'xml'. - ទ្រង់ទ្រាយដែលត្រូវប្រើប្រាស់នៅពេលកំពុងនាំចេញ។ ជម្រើសដែលអាចប្រើប្រាស់គឺ 'xml' ឬ 'csv'។ លំនាំដើមទៅកាន់ 'xml'។ - Exports the content of a database to standard output in the specified format. នាំចេញខ្លឹមសារនៃមូលដ្ឋានទិន្នន័យទៅជាលទ្ធផលស្តង់ដារក្នុងទម្រង់ដែលបានបញ្ជាក់នេះ។ @@ -8202,18 +8674,6 @@ Kernel: %3 %4 file empty ឯកសារទទេ - - malformed string - ជួរអក្សរដែលមានទម្រង់មិនត្រឹមត្រូវ - - - missing closing quote - កំពុងបាត់សម្រង់បិទ - - - %1: (row, col) %2,%3 - %1: (ជួរដេក, ជួរឈរ) %2,%3 - AES 256-bit AES 256 ប៊ីត @@ -8658,13 +9118,89 @@ This option is deprecated, use --set-key-file instead. - Unsupported KDF type, cannot decrypt json file + Unknown passkeys error - Unknown passkeys error + Invalid KDF iterations, cannot decrypt json file + + Unsupported format, ensure your Bitwarden export is password-protected + + + + Only PBKDF and Argon2 are supported, cannot decrypt json file + + + + Reset Shortcuts + + + + Double click an action to change its shortcut + + + + Filter... + + + + Shortcut Conflict + + + + Shortcut %1 conflicts with '%2'. Overwrite shortcut? + + + + Cannot generate valid passphrases because the wordlist is too short + + + + Encrypted files are not supported. + + + + Proton Pass Import + + + + Delete plugin data? + លុបទិន្នន័យនៅក្នុងកម្មវិធីជំនួយ? + + + Delete plugin data from Entry(s)? + + + + Passkey + + + + Format to use when exporting. Available choices are 'xml', 'csv' or 'html'. Defaults to 'xml'. + + + + start minimized to the system tray + + + + malformed string, possible unescaped delimiter + + + + missing closing delimiter + + + + %1, row: %2, column: %3 + + + + Tags + ស្លាក + QtIOCompressor @@ -8700,6 +9236,37 @@ This option is deprecated, use --set-key-file instead. បញ្ហា zlib ខាងក្នុង៖ + + RemoteHandler + + Command `%1` did not finish in time. Process was killed. + + + + Failed to upload merged database. Command `%1` did not finish in time. Process was killed. + + + + Invalid download parameters provided. + + + + Command `%1` failed to download database. + + + + Invalid database pointer or upload parameters provided. + + + + Command `%1` exited with status code: %2 + + + + Failed to upload merged database. Command `%1` exited with status code: %2 + + + ReportsWidgetBrowserStatistics @@ -8766,6 +9333,10 @@ This option is deprecated, use --set-key-file instead. Exclude from reports មិនរាប់បញ្ចូលពីរបាយការណ៍ + + Expire Entry(s)… + + Only show entries that have a URL @@ -8782,36 +9353,33 @@ This option is deprecated, use --set-key-file instead. (Expired) + + Delete plugin data from Entry(s)… + + ReportsWidgetHealthcheck - Hover over reason to show additional details. Double-click entries to edit. - ដាក់ពីលើហេតុផលដើម្បីបង្ហាញព័ត៌មានលម្អិតបន្ថែម។ ចុចទ្វេដងលើទិន្នន័យបញ្ចូលដើម្បីកែ។ + Show expired entries + - Bad - Password quality - មិនល្អ + (Expired) + + + + Hover over reason to show additional details. Double-click entries to edit. + ដាក់ពីលើហេតុផលដើម្បីបង្ហាញព័ត៌មានលម្អិតបន្ថែម។ ចុចទ្វេដងលើទិន្នន័យបញ្ចូលដើម្បីកែ។ Bad — password must be changed មិនល្អ - ត្រូវតែផ្លាស់ប្តូរពាក្យសម្ងាត់ - - Poor - Password quality - ខ្សោយ - Poor — password should be changed ខ្សោយ - គួរតែផ្លាស់ប្តូរពាក្យសម្ងាត់ - - Weak - Password quality - ខ្សោយ - Weak — consider changing the password ខ្សោយ — សូមពិចារណាផ្លាស់ប្តូរពាក្យសម្ងាត់នេះ @@ -8860,18 +9428,14 @@ This option is deprecated, use --set-key-file instead. Exclude from reports មិនរាប់បញ្ចូលពីរបាយការណ៍ - - Show expired entries - + + Expire Entry(s)… + Show entries that have been excluded from reports - - (Expired) - - ReportsWidgetHibp @@ -8967,6 +9531,10 @@ This option is deprecated, use --set-key-file instead. Exclude from reports មិនរាប់បញ្ចូលពីរបាយការណ៍ + + Expire Entry(s)… + + ReportsWidgetPasskeys @@ -9208,6 +9776,14 @@ This option is deprecated, use --set-key-file instead. No agent running, cannot list identities. មិនអាចចុះបញ្ជីអត្តសញ្ញាណបានដោយសារគ្មានភ្នាក់ងារដែលកំពុងដំណើរការ ។ + + Failed to remove all SSH identities from agent. + + + + All SSH identities removed from agent. + + SearchHelpWidget @@ -9493,29 +10069,6 @@ This option is deprecated, use --set-key-file instead. នាំចេញទៅ %1 - - ShortcutSettingsWidget - - Double click an action to change its shortcut - - - - Shortcut Conflict - - - - Filter... - - - - Shortcut %1 conflicts with '%2'. Overwrite shortcut? - - - - Reset Shortcuts - - - TagModel @@ -9805,11 +10358,15 @@ Example: JBSWY3DPEHPK3PXP រកមិនឃើញឃីហាតវែរទេ - <p>If you own a <a href="https://www.yubico.com/">YubiKey</a> or <a href="https://onlykey.io">OnlyKey</a>, you can use it for additional security.</p><p>The key requires one of its slots to be programmed as <a href="https://docs.yubico.com/yesdk/users-manual/application-otp/challenge-response.html">HMAC-SHA1 Challenge-Response</a>.</p> + Refresh hardware keys - Refresh hardware keys + <p>If you own a <a href="https://www.yubico.com/">YubiKey</a> or <a href="https://onlykey.io">OnlyKey</a>, you can use it for additional security.</p><p>The key requires one of its slots to be programmed with <a href="https://keepassxc.org/docs/#faq-yubikey-howto">Challenge-Response</a>.</p> + + + + Hardware keys found, but no slots are configured diff --git a/share/translations/keepassxc_ko.ts b/share/translations/keepassxc_ko.ts index ae3beaad0..85f9e87c3 100644 --- a/share/translations/keepassxc_ko.ts +++ b/share/translations/keepassxc_ko.ts @@ -217,18 +217,50 @@ You must restart the application to set the new language. Would you like to restart now? 새 언어를 적용하려면 프로그램을 다시 시작해야 합니다. 지금 다시 시작하시겠습니까? - - Reset Settings? - 설정을 초기화하시겠습니까? - - - Are you sure you want to reset all general and security settings to default? - 모든 일반 설정과 보안 설정을 초기화하시겠습니까? - Select backup storage directory 백업 저장 디렉터리 선택 + + Confirm Reset + + + + Are you sure you want to reset all settings to default? + + + + Import KeePassXC Settings + + + + Failed to import settings from %1, not a valid settings file. + + + + Export KeePassXC Settings + + + + Small + + + + Normal + + + + Medium + + + + Large + + + + Custom + + ApplicationSettingsWidgetGeneral @@ -262,7 +294,7 @@ recent files - 최근 파일 + 개 최근 파일 Load previously open databases on startup @@ -280,25 +312,6 @@ Include beta releases when checking for updates 업데이트를 확인할 때 베타 릴리스 포함 - - On database unlock, show entries that - 데이터베이스 잠금을 해제할 때 다음 항목 표시 - - - have expired - On database unlock, show entries that... - 이미 만료됨 - - - days - On database unlock, show entries that will expire within %1 days - 일 후에 만료됨 - - - will expire within - On database unlock, show entries that... - - File Management 파일 관리 @@ -323,22 +336,10 @@ Backup database file before saving 저장하기 전에 데이터베이스 파일 백업 - - Backup destination - 백업 대상 - - - Specifies the database backup file location. Occurrences of "{DB_FILENAME}" are replaced with the filename of the saved database without extension. {TIME:<format>} is replaced with the backup time, see https://doc.qt.io/qt-5/qdatetime.html#toString. <format> defaults to format string "dd_MM_yyyy_hh-mm-ss". - yyyy_MM_dd_hh-mm-ss - {DB_FILENAME}.old.kdbx {DB_FILENAME}.old.kdbx - - Choose... - 선택... - Use alternative saving method (may solve problems with Dropbox, Google Drive, GVFS, etc.) 대체 저장 방식 사용(Dropbox, Google 드라이브, GVFS 등 문제 해결) @@ -418,7 +419,7 @@ Show passwords in color - 암호 표시 시 색상 적용 + 암호 표시 시 글자 종류별로 색상 적용 Use monospaced font for notes @@ -505,6 +506,71 @@ Remember last typed entry for: 마지막으로 입력한 항목 기억 시간: + + On database unlock, show entries that will expire within + + + + On database unlock, show entries that will expire within + + + + days + number of days warning for password expiration + 일 내에 만료됨 + + + Destination format: + + + + <html><head/><body><p><span style=" font-weight:600;">{DB_FILENAME}</span> is replaced with the filename of the saved database without extension</p><p><span style=" font-weight:600;">{TIME:&lt;format&gt;}</span> is replaced with the specified time format (default: dd_MM_yyyy_hh-mm-ss)</p><p>See the User Guide for more details</p></body></html> + + + + Choose folder... + + + + Show confirmation before moving entries to recycle bin + + + + Copy data on double clicking field in entry view + + + + Show toolbar + 도구 모음 보이기 + + + Show the menu bar by pressing the Alt key + + + + Show menubar + + + + Import settings… + + + + Export settings… + + + + Open browser on double clicking URL field in entry view + + + + Font size: + + + + Font size selection + + ApplicationSettingsWidgetSecurity @@ -570,18 +636,6 @@ Hide passwords in the entry preview panel 항목 미리 보기 패널에서 암호 숨기기 - - Hide entry notes by default - 기본값으로 암호 숨기기 - - - Move entries to recycle bin without confirmation - 항목을 묻지 않고 휴지통으로 이동 - - - Enable double click to copy the username/password entry columns - 두 번 클릭으로 사용자 이름/암호 항목 열에서 복사 사용 - Privacy 개인 정보 @@ -594,6 +648,18 @@ Hide TOTP in the entry preview panel 항목 미리 보기 패널에서 TOTP 숨기기 + + Lock databases when switching user + 사용자를 전환할 때 데이터베이스 잠금 + + + Lock Options + + + + Hide notes in the entry preview panel + + AutoType @@ -641,20 +707,6 @@ Entry does not have attribute for PICKCHARS: %1 항목에 PICKCHARS 속성이 없음: %1 - - Invalid conversion type: %1 - 잘못된 변환 형식: %1 - - - Invalid conversion syntax: %1 - 잘못된 변환 문법: %1 - - - Invalid regular expression syntax %1 -%2 - 잘못된 정규 표현식 문법 %1 -%2 - Invalid placeholder: %1 잘못된 자리 비움자: %1 @@ -714,7 +766,7 @@ Trying to send invalid keyboard symbol. - + 잘못된 키보드 기호를 보내려고 시도하고 있습니다. @@ -882,28 +934,29 @@ Please select the correct database for saving credentials. KeePassXC - Passkey credentials - KeePassXC - Passkey 자격 증명 + KeePassXC - 패스키 자격 증명 Add to existing entry - + 기존 항목에 추가 Existing passkey found. Do you want to register a new passkey for: - + 기존 패스키를 찾았습니다. +다음에 대한 새 패스키를 등록하시겠습니까?: Select the existing passkey and press Update to replace it. - + 기존 패스키를 선택한 후 업데이트를 누르면 대체합니다. Authenticate passkey credentials for: - + 다음에 대하여 패스키 자격 증명 인증: Do you want to register a passkey for: - + 다음에 대한 패스키를 등록하시겠습니까?: @@ -952,7 +1005,7 @@ Do you want to delete the entry? %1 (Passkey) - %1(Passkey) + %1(패스키) KeePassXC - Create a new group @@ -980,24 +1033,25 @@ Do you want to delete the entry? Passkey - Passkey + 패스키 KeePassXC - Passkey credentials - KeePassXC - Passkey 자격 증명 + KeePassXC - 패스키 자격 증명 Register a new passkey to this entry: - + 이 항목에 새 패스키 등록: KeePassXC - Update passkey - + KeePassXC - 패스키 업데이트 Entry already has a passkey. Do you want to overwrite the passkey in %1 - %2? - + 항목에 이미 패스키가 있습니다. +%1 - %2에 패스키를 덮어쓰시겠습니까? Register @@ -1022,10 +1076,6 @@ Do you want to overwrite the passkey in %1 - %2? General 일반 - - Browsers installed as snaps are currently not supported. - Snap으로 설치한 브라우저는 지원하지 않습니다. - Enable integration for these browsers: 다음 브라우저에 통합: @@ -1197,18 +1247,6 @@ Do you want to overwrite the passkey in %1 - %2? Custom extension ID 사용자 정의 확장 기능 ID - - Due to Snap sandboxing, you must run a script to enable browser integration.<br />You can obtain this script from %1 - Snap 샌드박스로 인하여 브라우저 확장 기능을 사용하려면 스크립트를 실행해야 합니다.<br />%1에서 스크립트를 확인할 수 있습니다 - - - KeePassXC-Browser is needed for the browser integration to work. <br />Download it for %1 and %2 and %3. %4 - 브라우저 통합 기능을 사용하려면 KeePassXC-브라우저가 필요합니다.<br />%1, %2, %3, %4용으로 다운로드할 수 있습니다. - - - Please see special instructions for browser extension use below - 브라우저 확장 기능을 위한 추가 절차를 참조하십시오 - Executable Files 실행 파일 @@ -1251,10 +1289,18 @@ Do you want to overwrite the passkey in %1 - %2? Allows using insecure http://localhost with passkeys for testing purposes. - + 시험 목적으로 보안상 안전하지 않은 http://localhost에 패스키 사용을 허용합니다. Allow using localhost with passkeys + localhost에 패스키 사용 허용 + + + KeePassXC-Browser is needed for the browser integration to work. <br />Download it for %1 and %2 and %3. + 브라우저 통합을 사용하려면 KeePassXC-브라우저가 필요합니다.<br />%1, %2, %3용으로 다운로드할 수 있습니다. + + + Browsers installed using Snap or Flatpak are not supported with exception to Firefox installed using Snap. @@ -1399,6 +1445,20 @@ Do you want to overwrite the passkey in %1 - %2? Imported from CSV file: %1 CSV 파일에서 가져옴: %1 + + No Title Selected + 선택한 제목 없음 + + + No title column was selected, entries will be hard to tell apart. +Are you sure you want to import? + 제목 열을 선택하지 않았습니다. 개별 항목을 구분하기 어려울 수 있습니다. +계속 가져오시겠습니까? + + + Tags + 태그 + CsvParserModel @@ -1462,6 +1522,14 @@ Backup database located at %2 Recycle Bin 휴지통 + + Database file read error. + + + + No file path was provided. + + DatabaseOpenDialog @@ -1610,14 +1678,6 @@ To prevent this error from appearing, you must go to "Database Settings / S <p>In addition to a password, you can use a secret file to enhance the security of your database. This file can be generated in your database's security settings.</p><p>This is <strong>not</strong> your *.kdbx database file!</p> <p>데이터베이스 파일의 보안을 개선할 수 있도록 암호 외에도 비밀 파일을 사용할 수 있습니다. 해당 파일은 데이터베이스 보안 설정에서 생성할 수 있습니다.</p><p>이 파일은 *.kdbx 데이터베이스 파일이 <strong>아닙니다</strong>!</p> - - Click to add a key file. - 키 파일을 추가하려면 클릭하십시오. - - - <a href="#" style="text-decoration: underline">I have a key file</a> - <a href="#" style="text-decoration: underline">키 파일이 있음</a> - Use hardware key [Serial: %1] 하드웨어 키 사용 [일련 번호: %1] @@ -1654,6 +1714,18 @@ Are you sure you want to continue with this file?. Refresh Hardware Keys 하드웨어 키 새로 고침 + + Click to add a key file. + 키 파일을 추가하려면 클릭하십시오. + + + <a href="#" style="text-decoration: underline">I have a key file</a> + <a href="#" style="text-decoration: underline">키 파일이 있음</a> + + + Hardware keys found, but no slots are configured. + + DatabaseSettingWidgetMetaData @@ -1688,6 +1760,22 @@ Are you sure you want to continue with this file?. Maintenance 관리 + + KeeShare + KeeShare + + + Secret Service Integration + 비밀 서비스 통합 + + + Remote Sync + 원격 동기화 + + + Database Settings: %1 + + DatabaseSettingsWidgetBrowser @@ -1858,14 +1946,14 @@ Are you sure you want to continue without a password? Weak password 약한 암호 - - You must enter a stronger password to protect your database. - 데이터베이스를 보호하려면 더 강력한 암호를 입력해야 합니다. - This is a weak password! For better protection of your secrets, you should choose a stronger password. 암호가 너무 약합니다! 기밀 정보를 보호하려면 더 강한 암호를 입력해야 합니다. + + The provided password does not meet the minimum quality requirement. + 지정한 암호가 최소 보안 조건을 만족하지 않습니다. + DatabaseSettingsWidgetEncryption @@ -2135,7 +2223,7 @@ add up to the specified amount at most. Limit the total size of history items per entry to: - 항목별 과거 기록 개수 제한: + 항목별 과거 기록 총 크기 제한: Move entries to a recycle bin group @@ -2167,6 +2255,50 @@ removed from the database. Autosave delay since last change checkbox 마지막 체크 상자 변경 후 자동 저장 대기 시간 + + Public Database Metadata + + + + Warning: the following settings are not encrypted. + + + + Display name: + + + + Publically visible display name used on the unlock dialog + + + + Database public display name + + + + Display color: + + + + Publically visible color used on the unlock dialog + + + + Database public display color chooser + + + + Clear + 비우기 + + + Display icon: + + + + Select Database Icon + + DatabaseSettingsWidgetKeeShare @@ -2262,6 +2394,141 @@ removed from the database. 데이터베이스 설명 필드 + + DatabaseSettingsWidgetRemote + + Sync Commands + 동기화 명령 + + + Remove + 삭제 + + + Command Settings + 명령 설정 + + + Name + 이름 + + + Save + 저장 + + + Download + 다운로드 + + + Command: + 명령: + + + Download command field + 다운로드 명령 필드 + + + e.g.: "sftp user@hostname" or "scp user@hostname:DatabaseOnRemote.kdbx {TEMP_DATABASE}" + 예제: "sftp user@hostname" 또는 "scp user@hostname:DatabaseOnRemote.kdbx {TEMP_DATABASE}" + + + Input: + 입력: + + + Download input field + 다운로드 입력 필드 + + + Upload + 업로드 + + + Upload command field + 업로드 명령 필드 + + + e.g.: "sftp user@hostname" or "scp {TEMP_DATABASE} user@hostname:DatabaseOnRemote.kdbx" + 예제: "sftp user@hostname" 또는 "scp {TEMP_DATABASE} user@hostname:DatabaseOnRemote.kdbx" + + + Upload input field + 업로드 입력 필드 + + + Name cannot be empty. + 이름을 비워 둘 수 없습니다. + + + Test + 시험 + + + Download command cannot be empty. + 다운로드 명령을 비워 둘 수 없습니다. + + + Download failed with error: %1 + 다운로드 실패, 오류: %1 + + + Download finished, but file %1 could not be found. + 다운로드가 완료되었지만 %1 파일을 찾을 수 없습니다. + + + Download successful. + 다운로드에 성공했습니다. + + + Save Remote Settings + 원격 설정 저장 + + + You have unsaved changes. Do you want to save them? + 저장하지 않은 변경 사항이 있습니다. 저장하시겠습니까? + + + e.g.: +get DatabaseOnRemote.kdbx {TEMP_DATABASE} +exit +--- +{TEMP_DATABASE} is used as placeholder to store the database in a temporary location +The command has to exit. In case of `sftp` as last command `exit` has to be sent + + 예제.: +get DatabaseOnRemote.kdbx {TEMP_DATABASE} +exit +--- +{TEMP_DATABASE}는 임시 위치에 저장된 데이터베이스를 가리키는 자리 비움자입니다 +명령은 종료되어야 합니다. `sftp`의 경우 마지막 `exit` 명령을 전송해야 합니다 + + + + e.g.: +put {TEMP_DATABASE} DatabaseOnRemote.kdbx +exit +--- +{TEMP_DATABASE} is used as placeholder to store the database in a temporary location +The command has to exit. In case of `sftp` as last command `exit` has to be sent + + 예제.: +put {TEMP_DATABASE} DatabaseOnRemote.kdbx +exit +--- +{TEMP_DATABASE}는 임시 위치에 저장된 데이터베이스를 가리키는 자리 비움자입니다 +명령은 종료되어야 합니다. `sftp`의 경우 마지막 `exit` 명령을 전송해야 합니다 + + + + Timeout: + + + + seconds + + + DatabaseTabWidget @@ -2335,6 +2602,11 @@ This is definitely a bug, please report it to the developers. Database tab name modifier %1 [잠김] + + %1 [Temporary] + Database tab name modifier + %1 [임시] + DatabaseWidget @@ -2457,26 +2729,6 @@ Save changes? File has changed 파일 변경됨 - - The database file has changed. Do you want to load the changes? - 데이터베이스 파일이 변경되었습니다. 변경 사항을 불러오시겠습니까? - - - Merge Request - 요청 합치기 - - - The database file has changed and you have unsaved changes. -Do you want to merge your changes? - 데이터베이스 파일이 변경되었고 저장하지 않은 변경 사항이 있습니다. -변경 사항을 합치겠습니까? - - - Could not open the new database file while attempting to autoreload. -Error: %1 - 자동으로 다시 불러오려는 중 새 데이터베이스 파일을 열 수 없었습니다. -오류: %1 - Disable safe saves? 안전 저장을 비활성화 하시겠습니까? @@ -2528,6 +2780,86 @@ Disable safe saves and try again? Database tab name modifier %1 [새 데이터베이스] + + Remote Sync did not contain any download or upload commands. + 원격 동기화에 다운로드나 업로드 명령이 없습니다. + + + Remote sync '%1' completed successfully! + '%1' 원격 동기화에 성공했습니다! + + + Remote sync '%1' failed: %2 + '%1' 원격 동기화 실패: %2 + + + Error while saving database %1: %2 + %1 데이터베이스를 저장하는 중 오류 발생: %2 + + + Downloading... + 다운로드 중... + + + Uploading... + 업로드 중... + + + Syncing... + 동기화 중... + + + Remove passkey from entry + 항목에서 패스키 삭제 + + + Do you want to remove the passkey from this entry? + 이 항목에서 패스키를 삭제하시겠습니까? + + + The database file "%1" was modified externally + + + + Do you want to load the changes? + + + + Reload database + + + + Reloading database… + + + + Reload canceled + + + + Reload successful + + + + Reload pending user action… + + + + The database file "%1" was modified externally.<br>How would you like to proceed?<br><br>Merge all changes<br>Ignore the changes on disk until save<br>Discard unsaved changes + + + + The database file "%1" was modified externally.<br>How would you like to proceed?<br><br>Merge all changes then save<br>Overwrite the changes on disk<br>Discard unsaved changes + + + + Database file overwritten. + + + + Database file on disk cannot be unlocked with current credentials.<br>Enter new credentials and/or present hardware key to continue. + + EditEntryWidget @@ -2579,10 +2911,6 @@ Disable safe saves and try again? n/a 없음 - - (encrypted) - (암호화됨) - Select private key 비밀 키 선택 @@ -2685,6 +3013,10 @@ Would you like to correct it? %n year(s) %n년 + + Failed to decrypt SSH key, ensure password is correct. + SSH 키를 복호화할 수 없습니다. 암호가 올바른지 확인하십시오. + EditEntryWidgetAdvanced @@ -2856,18 +3188,10 @@ Would you like to correct it? Skip Auto-Submit for this entry 이 항목 자동 제출 건너뛰기 - - Only send this setting to the browser for HTTP Auth dialogs. If enabled, normal login forms will not show this entry for selection. - 웹 브라우저의 HTTP 인증 대화 상자에만 이 설정을 사용합니다. 활성화하면 일반 로그인 폼 선택 목록에 이 항목을 표시하지 않습니다. - Use this entry only with HTTP Basic Auth HTTP Basic 인증에만 이 항목 사용 - - Do not send this setting to the browser for HTTP Auth dialogs. If enabled, HTTP Auth dialogs will not show this entry for selection. - 이 설정을 브라우저의 HTTP 인증 대화 상자로 보내지 않습니다. 이 옵션을 사용하면 HTTP 인증 대화 상자에서 이 항목을 숨깁니다. - Do not use this entry with HTTP Basic Auth HTTP Basic 인증에 이 항목 사용하지 않기 @@ -2886,11 +3210,19 @@ Would you like to correct it? These settings affect the entry's behaviour with the browser extension. - + 이 설정은 브라우저 확장 기능에서 항목을 사용하는 방법에 영향을 줍니다. Additional URLs - + 추가 URL + + + Only send this entry to the browser for HTTP Auth dialogs. If enabled, normal login forms will not show this entry for selection. + 브라우저의 HTTP 인증 대화 상자에 이 항목만 보냅니다. 이 옵션을 사용하면 일반 로그인 폼에는 이 항목을 선택할 수 있도록 표시하지 않습니다. + + + Do not send this entry to the browser for HTTP Auth dialogs. If enabled, HTTP Auth dialogs will not show this entry for selection. + 이 항목을 브라우저의 HTTP 인증 대화 상자에 보내지 않습니다. 이 옵션을 사용하면 HTTP 인증 대화 상자에는 이 항목을 선택할 수 있도록 표시하지 않습니다. @@ -3114,6 +3446,10 @@ Would you like to correct it? seconds + + Clear agent + + EditGroupWidget @@ -3194,7 +3530,7 @@ Would you like to correct it? Do not use HTTP Auth toggle for this and sub groups - 이 그룹과 하위 그룹의 항목을 HTTP 인증에 사용하지 않기 + 이 그룹과 하위 그룹의 항목을 HTTP 인증에 사용하지 않기 전환 Omit WWW subdomain from matching: @@ -3556,6 +3892,24 @@ This may cause the affected plugins to malfunction. %1 - Clone %1 - 사본 + + Passkey + 패스키 + + + Invalid conversion type: %1 + 잘못된 변환 형식: %1 + + + Invalid conversion syntax: %1 + 잘못된 변환 문법: %1 + + + Invalid regular expression syntax %1 +%2 + 잘못된 정규 표현식 문법 %1 +%2 + EntryAttachments @@ -3564,6 +3918,21 @@ This may cause the affected plugins to malfunction. 파일 "%1"을(를) 열 수 없음 + + EntryAttachmentsDialog + + Form + + + + File name + + + + File contents... + + + EntryAttachmentsModel @@ -3601,14 +3970,6 @@ This may cause the affected plugins to malfunction. Remove 삭제 - - Rename selected attachment - 선택한 첨부 파일 이름 바꾸기 - - - Rename - 이름 바꾸기 - Open selected attachment 선택한 첨부 파일 열기 @@ -3649,7 +4010,7 @@ This may cause the affected plugins to malfunction. Are you sure you want to overwrite the existing file "%1" with the attachment? - 기존 파일 "%1"의 내용을 첨부 항목으로 덮어 쓰시겠습니까? + 기존 파일 "%1"의 내용을 첨부 항목으로 덮어쓰시겠습니까? Confirm overwrite @@ -3723,6 +4084,18 @@ Would you like to overwrite the existing attachment? 첨부 "%1"이(가) 이미 있습니다. 기존 첨부 항목을 덮어쓰시겠습니까? + + New + + + + Preview + 미리 보기 + + + Failed to preview an attachment: Attachment not found + + EntryAttributesModel @@ -3921,6 +4294,10 @@ Would you like to overwrite the existing attachment? Background Color 배경색 + + Group Path + + EntryPreviewWidget @@ -4316,6 +4693,14 @@ You can enable the DuckDuckGo website icon service in the security section of th Url URL + + Could not load key file. + + + + Could not open remote database. Password or key file may be incorrect. + + ImportWizardPageSelect @@ -4419,6 +4804,44 @@ You can enable the DuckDuckGo website icon service in the security section of th KeePass1 Database KeePass1 데이터베이스 + + Proton Pass (.json) + + + + Proton Pass JSON Export + + + + Temporary Database + + + + Command: + 명령: + + + e.g.: "sftp user@hostname" or "scp user@hostname:DatabaseOnRemote.kdbx {TEMP_DATABASE}" + 예제: "sftp user@hostname" 또는 "scp user@hostname:DatabaseOnRemote.kdbx {TEMP_DATABASE}" + + + Input: + 입력: + + + e.g.: +get DatabaseOnRemote.kdbx {TEMP_DATABASE} +exit +--- +{TEMP_DATABASE} is used as placeholder to store the database in a temporary location +The command has to exit. In case of `sftp` as last commend `exit` has to be sent + + + + + Remote Database (.kdbx) + + KMessageWidget @@ -5504,7 +5927,7 @@ Are you sure you want to continue with this file? Show Menubar - + 메뉴 표시줄 표시 Show Toolbar @@ -5559,12 +5982,6 @@ This version is not meant for production use. Expect some bugs and minor issues, this version is meant for testing purposes. 알림: KeePassXC의 미리 보기 버전을 사용하고 있습니다. 이 버전은 시험용 버전이므로 버그나 사소한 문제가 발생할 수 있습니다. - - - WARNING: Your Qt version may cause KeePassXC to crash with an On-Screen Keyboard. -We recommend you use the AppImage available on our downloads page. - 경고: 사용 중인 Qt 버전에서 KeePassXC를 화상 키보드와 사용했을 때 충돌할 수 있습니다. -다운로드 페이지에 있는 AppImage 사용을 추천합니다. No Tags @@ -5632,11 +6049,15 @@ We recommend you use the AppImage available on our downloads page. Passkeys… - Passkey… + 패스키… Import Passkey - Passkey 가져오기 + 패스키 가져오기 + + + Remote S&ync… + 원격 동기화(&Y)… Quit Application @@ -5742,6 +6163,10 @@ We recommend you use the AppImage available on our downloads page. Show Password Generator 암호 생성기 표시 + + Remove Passkey From Entry + 항목에서 패스키 삭제 + Perform Auto-Type: {USERNAME} 자동 입력 실행: {USERNAME} @@ -5856,7 +6281,7 @@ We recommend you use the AppImage available on our downloads page. Toggle Show Menubar - + 메뉴 표시줄 표시 전환 Toggle Show Toolbar @@ -5886,6 +6311,34 @@ We recommend you use the AppImage available on our downloads page. Toggle Allow Screen Capture 화면 캡처 허용 전환 + + Show Group Panel + + + + Toggle Show Group Panel + + + + Setup Remote Sync… + 원격 동기화 설정… + + + Password Generator + 암호 생성기 + + + E&xpire Entry… + + + + Clear SSH Agent + + + + Clear all identities in ssh-agent + + ManageDatabase @@ -6036,6 +6489,25 @@ We recommend you use the AppImage available on our downloads page. 새 데이터베이스 표시 이름과 추가 설명(선택)을 입력하십시오: + + NewEntryAttachmentsDialog + + Attachment name cannot be empty + + + + Attachment with the same name already exists + + + + Save attachment + 첨부 항목 저장 + + + New entry attachment + + + NixUtils @@ -6223,6 +6695,10 @@ We recommend you use the AppImage available on our downloads page. Unexpected EOF when writing private key 비밀 키를 기록하는 중 예상하지 못한 곳에서 파일이 끝남 + + (encrypted) + (암호화됨) + OpenSSHKeyGenDialog @@ -6247,7 +6723,7 @@ We recommend you use the AppImage available on our downloads page. PasskeyExportDialog KeePassXC - Passkey Export - KeePassXC - Passkey 내보내기 + KeePassXC - 패스키 내보내기 Filenames will be generated with title and .passkey file extension. @@ -6271,14 +6747,14 @@ We recommend you use the AppImage available on our downloads page. Export the following passkey entries. - + 지정한 패스키 항목을 내보냅니다. PasskeyExporter KeePassXC: Passkey Export - KeePassXC: Passkey 내보내기 + KeePassXC: 패스키 내보내기 File "%1.passkey" already exists. @@ -6305,7 +6781,7 @@ Do you want to overwrite it? PasskeyImportDialog KeePassXC - Passkey Import - KeePassXC - Passkey 가져오기 + KeePassXC - 패스키 가져오기 Username: %1 @@ -6321,7 +6797,7 @@ Do you want to overwrite it? Import Passkey - Passkey 가져오기 + 패스키 가져오기 Import @@ -6345,22 +6821,22 @@ Do you want to overwrite it? Import the following passkey: - + 다음 패스키 가져오기: Import the following passkey to this entry: - + 이 항목으로 다음 패스키 가져오기: Default passkeys group (Imported Passkeys) - + 기본 패스키 그룹(가져온 패스키) PasskeyImporter Passkey file - Passkey 파일 + 패스키 파일 All files @@ -6376,25 +6852,27 @@ Do you want to overwrite it? Open passkey file - + 패스키 파일 열기 Cannot import passkey - + 패스키를 가져올 수 없음 Cannot import passkey file "%1". Data is missing. - + 패스키 파일 "%1"을(를) 열 수 없습니다. 데이터가 빠져 있습니다. Cannot import passkey file "%1". The following data is missing: %2 - + 패스키 파일 "%1"을(를) 가져올 수 없습니다. +다음 데이터가 빠졌습니다: +%2 Cannot import passkey file "%1". Private key is missing or malformed. - + 패스키 파일 "%1"을(를) 가져올 수 없습니다. 개인 키가 빠졌거나 잘못되었습니다. @@ -6575,10 +7053,6 @@ The following data is missing: Also choose from: 다음에서도 선택: - - Excluded characters: "0", "1", "l", "I", "O", "|", "﹒" - 제외할 글자: "0", "1", "l", "I", "O", "|", "﹒" - Exclude look-alike characters 비슷하게 생긴 문자 제외 @@ -6603,10 +7077,6 @@ The following data is missing: Word Count: 단어 개수: - - Character Count: - 글자 수: - Word Case: 대소문자: @@ -6619,10 +7089,6 @@ The following data is missing: Add custom wordlist 사용자 정의 단어 목록 추가 - - character - 글자 - Close 닫기 @@ -6729,6 +7195,22 @@ Do you want to overwrite it? Special Characters 특수 문자 + + passwordLength + 암호 길이 + + + Characters: %1 + 글자 수: %1 + + + MIXED case + + + + Excluded characters: "0", "1", "l", "I", "O", "|", "﹒", "B", "8", "G", "6" + + PasswordWidget @@ -6796,6 +7278,21 @@ Do you want to overwrite it? 글자를 입력할 때마다 Tab 키 누르기(&T) + + PreviewEntryAttachmentsDialog + + Preview entry attachment + + + + No preview available + + + + Image format not supported + + + QMessageBox @@ -6812,7 +7309,7 @@ Do you want to overwrite it? Empty - 비어 있음 + 삭제 Remove @@ -7474,10 +7971,6 @@ Do you want to overwrite it? Invalid word count %1 잘못된 단어 개수 %1 - - The word list is too small (< 1000 items) - 단어 목록이 너무 작음(1000개 미만) - Title for the entry. 항목의 제목입니다. @@ -7622,10 +8115,6 @@ Do you want to overwrite it? Exit interactive mode. 대화형 모드를 종료합니다. - - Format to use when exporting. Available choices are 'xml' or 'csv'. Defaults to 'xml'. - 내보낼 때 사용할 형식입니다. 'xml', 'csv'를 사용할 수 있으며 기본값은 'xml'입니다. - Exports the content of a database to standard output in the specified format. 데이터베이스 내용을 지정한 형식으로 표준 출력으로 내보냅니다. @@ -8176,7 +8665,7 @@ CPU 아키텍처: %2 Argon2%1 (%2 rounds, %3 KB) - Argon2%1(%2회, %3 KB) + Argon2%1(%2라운드, %3 KB) SymmetricCipher::init: Invalid cipher mode. @@ -8214,18 +8703,6 @@ CPU 아키텍처: %2 file empty 파일이 비어 있음 - - malformed string - 잘못된 문자열 - - - missing closing quote - 닫는 따옴표 없음 - - - %1: (row, col) %2,%3 - %1: (줄, 칸) %2, %3 - AES 256-bit AES 256비트 @@ -8469,11 +8946,12 @@ CPU 아키텍처: %2 Set the key file for the database. This option is deprecated, use --set-key-file instead. - + 데이터베이스의 키 파일을 선택합니다. +이 옵션은 삭제될 예정입니다. --set-key-file 옵션을 대신 사용하십시오. Databases have been locked. - + 데이터베이스가 잠겼습니다. Attestation not supported @@ -8485,7 +8963,7 @@ This option is deprecated, use --set-key-file instead. Passkeys request canceled - Passkey 요청 취소됨 + 패스키 요청 취소됨 Invalid user verification @@ -8501,7 +8979,7 @@ This option is deprecated, use --set-key-file instead. Passkeys - Passkey + 패스키 AES initialization failed @@ -8670,13 +9148,89 @@ This option is deprecated, use --set-key-file instead. 단축키 - Unsupported KDF type, cannot decrypt json file + Unknown passkeys error + 알 수 없는 패스키 오류 + + + Invalid KDF iterations, cannot decrypt json file + 잘못된 KDF 반복 횟수, JSON 파일을 복호화할 수 없음 + + + Unsupported format, ensure your Bitwarden export is password-protected + 지원하지 않는 형식, Bitwarden 내보내기 파일이 암호로 보호되었는지 확인하십시오 + + + Only PBKDF and Argon2 are supported, cannot decrypt json file + PBKDF와 Argon2만 지원함, JSON 파일을 복호화할 수 없음 + + + Reset Shortcuts + 단축키 초기화 + + + Double click an action to change its shortcut + 동작을 두 번 클릭해서 단축키 변경 + + + Filter... + 필터... + + + Shortcut Conflict + 단축키 충돌 + + + Shortcut %1 conflicts with '%2'. Overwrite shortcut? + %1 단축키가 '%2'와(과) 충돌합니다. 단축키를 덮어쓰시겠습니까? + + + Cannot generate valid passphrases because the wordlist is too short - Unknown passkeys error + Encrypted files are not supported. + + Proton Pass Import + + + + Delete plugin data? + 플러그인 데이터를 삭제하시겠습니까? + + + Delete plugin data from Entry(s)? + + + + Passkey + 패스키 + + + Format to use when exporting. Available choices are 'xml', 'csv' or 'html'. Defaults to 'xml'. + + + + start minimized to the system tray + + + + malformed string, possible unescaped delimiter + + + + missing closing delimiter + + + + %1, row: %2, column: %3 + + + + Tags + 태그 + QtIOCompressor @@ -8712,6 +9266,37 @@ This option is deprecated, use --set-key-file instead. 내부 zlib 오류: + + RemoteHandler + + Command `%1` did not finish in time. Process was killed. + `%1` 명령이 시간 내에 완료되지 않았습니다. 프로세스가 종료되었습니다. + + + Failed to upload merged database. Command `%1` did not finish in time. Process was killed. + 병합된 데이터베이스를 업로드하지 못했습니다. `%1` 명령이 시간 내에 완료되지 않았습니다. 프로세스가 종료되었습니다. + + + Invalid download parameters provided. + 잘못된 다운로드 인자가 지정되었습니다. + + + Command `%1` failed to download database. + `%1` 명령으로 데이터베이스를 다운로드하지 못했습니다. + + + Invalid database pointer or upload parameters provided. + 잘못된 데이터베이스 포인터나 업로드 인자가 지정되었습니다. + + + Command `%1` exited with status code: %2 + `%1` 명령이 종료되면서 다음 상태 코드를 반환함: %2 + + + Failed to upload merged database. Command `%1` exited with status code: %2 + 병합된 데이터베이스를 업로드하지 못했습니다. `%1` 명령이 다음 상태 코드를 반환함: %2 + + ReportsWidgetBrowserStatistics @@ -8778,6 +9363,10 @@ This option is deprecated, use --set-key-file instead. Exclude from reports 보고서에서 제외 + + Expire Entry(s)… + + Only show entries that have a URL URL이 있는 항목만 표시 @@ -8794,36 +9383,33 @@ This option is deprecated, use --set-key-file instead. (Expired) (만료됨) + + Delete plugin data from Entry(s)… + + ReportsWidgetHealthcheck - Hover over reason to show additional details. Double-click entries to edit. - 이유 위에 마우스를 올려 두면 자세한 정보를 표시합니다. 항목을 두 번 클릭하면 편집할 수 있습니다. + Show expired entries + 만료된 항목 표시 - Bad - Password quality - 나쁨 + (Expired) + (만료됨) + + + Hover over reason to show additional details. Double-click entries to edit. + 이유 위에 마우스를 올려 두면 자세한 정보를 표시합니다. 항목을 두 번 클릭하면 편집할 수 있습니다. Bad — password must be changed 나쁨 — 암호를 변경해야 함 - - Poor - Password quality - 매우 약함 - Poor — password should be changed 매우 약함 — 암호 변경을 고려해야 함 - - Weak - Password quality - 약함 - Weak — consider changing the password 약함 — 암호 변경을 권장함 @@ -8872,18 +9458,14 @@ This option is deprecated, use --set-key-file instead. Exclude from reports 보고서에서 제외 - - Show expired entries - 만료된 항목 표시 + + Expire Entry(s)… + Show entries that have been excluded from reports 보고서에서 제외된 항목 표시 - - (Expired) - (만료됨) - ReportsWidgetHibp @@ -8979,6 +9561,10 @@ This option is deprecated, use --set-key-file instead. Exclude from reports 보고서에서 제외 + + Expire Entry(s)… + + ReportsWidgetPasskeys @@ -9036,15 +9622,15 @@ This option is deprecated, use --set-key-file instead. The passkey file will be vulnerable to theft and unauthorized use, if left unsecured. Are you sure you want to continue? - + 패스키 파일을 안전하게 보존하지 않으면 탈취 및 인증되지 않은 사용에 취약해질 수 있습니다. 계속 진행하시겠습니까? Please wait, list of entries with passkeys is being updated… - + 잠시 기다려 주십시오. 패스키가 있는 항목을 업데이트하는 중… No entries with passkeys. - + 패스키가 있는 항목이 없습니다. @@ -9220,6 +9806,14 @@ This option is deprecated, use --set-key-file instead. No agent running, cannot list identities. 에이전트가 실행 중이지 않아서 식별자 목록을 표시할 수 없습니다. + + Failed to remove all SSH identities from agent. + + + + All SSH identities removed from agent. + + SearchHelpWidget @@ -9394,11 +9988,11 @@ This option is deprecated, use --set-key-file instead. <html><head/><body><p>This setting does not override disabling recycle bin prompts </p></body></html> - + <html><head/><body><p>이 설정은 휴지통 프롬프트 비활성화를 재정의하지 않습니다 </p></body></html> <html><head/><body><p>This improves compatibility with certain applications which search for password without unlocking the database first.</p><p>But enabling this may also crash the client if the database can not be unlocked within a certain timeout. (Usually 25s, but may be a different value set in applications.) </p></body></html> - + <html><head/><body><p>이 옵션은 데이터베이스의 잠금을 해제하지 않고 암호를 검색하는 프로그램과의 호환성을 개선합니다.</p><p>그러나 이 옵션을 사용하면 데이터베이스가 지정한 시간 내에 잠금 해제될 수 없을 때 클라이언트를 충돌시킬 수도 있습니다.(대개 25초, 프로그램에 따라서 다른 설정을 사용할 수도 있음) </p></body></html> @@ -9505,29 +10099,6 @@ This option is deprecated, use --set-key-file instead. %1(으)로 내보내기 - - ShortcutSettingsWidget - - Double click an action to change its shortcut - 동작을 두 번 클릭해서 단축키 변경 - - - Shortcut Conflict - 단축키 충돌 - - - Filter... - 필터... - - - Shortcut %1 conflicts with '%2'. Overwrite shortcut? - %1 단축키가 '%2'와(과) 충돌합니다. 단축키를 덮어쓰시겠습니까? - - - Reset Shortcuts - 단축키 초기화 - - TagModel @@ -9816,14 +10387,18 @@ Example: JBSWY3DPEHPK3PXP No hardware keys detected 인식된 하드웨어 키 없음 - - <p>If you own a <a href="https://www.yubico.com/">YubiKey</a> or <a href="https://onlykey.io">OnlyKey</a>, you can use it for additional security.</p><p>The key requires one of its slots to be programmed as <a href="https://docs.yubico.com/yesdk/users-manual/application-otp/challenge-response.html">HMAC-SHA1 Challenge-Response</a>.</p> - <p><a href="https://www.yubico.com/">YubiKey</a>나 <a href="https://onlykey.io">OnlyKey</a>를 가지고 있다면 추가 보안에 사용할 수 있습니다</p><p>키 슬롯 중 하나를 <a href="https://docs.yubico.com/yesdk/users-manual/application-otp/challenge-response.html">HMAC-SHA1 Challenge-Response</a> 모드로 프로그램해야 합니다.</p> - Refresh hardware keys 하드웨어 키 새로 고침 + + <p>If you own a <a href="https://www.yubico.com/">YubiKey</a> or <a href="https://onlykey.io">OnlyKey</a>, you can use it for additional security.</p><p>The key requires one of its slots to be programmed with <a href="https://keepassxc.org/docs/#faq-yubikey-howto">Challenge-Response</a>.</p> + + + + Hardware keys found, but no slots are configured + + YubiKeyInterfacePCSC diff --git a/share/translations/keepassxc_lt.ts b/share/translations/keepassxc_lt.ts index b72ad7118..42f16efef 100644 --- a/share/translations/keepassxc_lt.ts +++ b/share/translations/keepassxc_lt.ts @@ -217,18 +217,50 @@ You must restart the application to set the new language. Would you like to restart now? Norėdami nustatyti naują kalbą, turite iš naujo paleisti programą. Ar norite iš naujo paleisti programą dabar? - - Reset Settings? - Atstatyti nustatymus? - - - Are you sure you want to reset all general and security settings to default? - Ar tikrai norite atstatyti kaip buvo visus bendruosius ir saugumo nustatymus? - Select backup storage directory Pasirinkite atsarginių kopijų saugojimo katalogą + + Confirm Reset + + + + Are you sure you want to reset all settings to default? + Ar norite atstatyti visus nustatymus į numatytąsias reikšmes? + + + Import KeePassXC Settings + Importuoti KeePassXC nustatymus + + + Failed to import settings from %1, not a valid settings file. + + + + Export KeePassXC Settings + Eksportuoti KeePassXC nustatymus + + + Small + + + + Normal + + + + Medium + + + + Large + + + + Custom + + ApplicationSettingsWidgetGeneral @@ -280,25 +312,6 @@ Include beta releases when checking for updates Įtraukti beta versijas, kai tikrinami atnaujinimai - - On database unlock, show entries that - Duomenų bazės atrakinimo metu rodyti įrašus, kurie - - - have expired - On database unlock, show entries that... - nustojo galioti - - - days - On database unlock, show entries that will expire within %1 days - dienos - - - will expire within - On database unlock, show entries that... - nustos galioti per - File Management Failų tvarkymas @@ -323,22 +336,10 @@ Backup database file before saving Išsaugoti duomenų bazę prieš išsaugant - - Backup destination - Atsarginės kopijos darymo vieta - - - Specifies the database backup file location. Occurrences of "{DB_FILENAME}" are replaced with the filename of the saved database without extension. {TIME:<format>} is replaced with the backup time, see https://doc.qt.io/qt-5/qdatetime.html#toString. <format> defaults to format string "dd_MM_yyyy_hh-mm-ss". - Nurodo duomenų bazės atsarginės kopijos failo vietą. Vietoj "{DB_FILENAME}" įrašomas išsaugotos duomenų bazės failo pavadinimas be plėtinio. {TIME:<format>} pakeičiamas atsarginės kopijos darymo laiku, žr. https://doc.qt.io/qt-5/qdatetime.html#toString. <format> Pagal numatytuosius nustatymus naudojama formato eilutė "dd_MM_yyyy_hh-mm-ss". - {DB_FILENAME}.old.kdbx {DB_FILENAME}.old.kdbx - - Choose... - Pasirinkti... - Use alternative saving method (may solve problems with Dropbox, Google Drive, GVFS, etc.) Naudoti alternatyvų išsaugojimo būdą (gali išspręsti Dropbox, Google Drive, GVFS ir kt. problemas). @@ -505,6 +506,71 @@ Remember last typed entry for: Prisiminti paskutinį įvestą įrašą: + + On database unlock, show entries that will expire within + + + + On database unlock, show entries that will expire within + + + + days + number of days warning for password expiration + dienos + + + Destination format: + Paskirties formatas: + + + <html><head/><body><p><span style=" font-weight:600;">{DB_FILENAME}</span> is replaced with the filename of the saved database without extension</p><p><span style=" font-weight:600;">{TIME:&lt;format&gt;}</span> is replaced with the specified time format (default: dd_MM_yyyy_hh-mm-ss)</p><p>See the User Guide for more details</p></body></html> + + + + Choose folder... + + + + Show confirmation before moving entries to recycle bin + + + + Copy data on double clicking field in entry view + + + + Show toolbar + Rodyti įrankių juostą + + + Show the menu bar by pressing the Alt key + + + + Show menubar + Rodyti meniu juostą + + + Import settings… + Importuoti nustatymus… + + + Export settings… + Eksportuoti nustatymus… + + + Open browser on double clicking URL field in entry view + + + + Font size: + Šrifto dydis: + + + Font size selection + Šrifto dydžio pasirinkimas + ApplicationSettingsWidgetSecurity @@ -570,18 +636,6 @@ Hide passwords in the entry preview panel Paslėpti slaptažodžius įrašo peržiūros skydelyje - - Hide entry notes by default - Pagal numatymą, slėpti įrašo pastabas - - - Move entries to recycle bin without confirmation - Perkelti įrašus į šiukšliadėžę be patvirtinimo - - - Enable double click to copy the username/password entry columns - Įgalinkite dvigubą paspaudimą, kad nukopijuotumėte slapyvardžio ir slaptažodžio įrašų stulpelius - Privacy Privatumas @@ -594,6 +648,18 @@ Hide TOTP in the entry preview panel + + Lock databases when switching user + Užrakinti duomenų bazes perjungiant naudotoją + + + Lock Options + + + + Hide notes in the entry preview panel + + AutoType @@ -641,19 +707,6 @@ Entry does not have attribute for PICKCHARS: %1 Įrašas neturi PICKCHARS atributo: %1 - - Invalid conversion type: %1 - Netinkamas vertimo tipas: %1 - - - Invalid conversion syntax: %1 - Netinkama vertimo sintaksė: %1 - - - Invalid regular expression syntax %1 -%2 - Netinkama regexp sintaksė - Invalid placeholder: %1 Netinkamas žymeklis: %1 @@ -821,7 +874,7 @@ Ctrl+4 - naudoti virtualią klaviatūrą (tik Windows) Undo - + Atšaukti @@ -853,7 +906,7 @@ Prisijungimo duomenų įrašymui, pasirinkite teisingą duomenų bazę. Update - + Atnaujinti Authenticate @@ -877,7 +930,7 @@ Prisijungimo duomenų įrašymui, pasirinkite teisingą duomenų bazę. Username: %1 - + Naudotojo vardas: %1 KeePassXC - Passkey credentials @@ -1020,10 +1073,6 @@ Do you want to overwrite the passkey in %1 - %2? General Bendra - - Browsers installed as snaps are currently not supported. - Šiuo metu nepalaikomos naršyklės, įdiegtos kaip snapai. - Enable integration for these browsers: Įjungti integraciją šioms naršyklėms: @@ -1195,18 +1244,6 @@ Do you want to overwrite the passkey in %1 - %2? Custom extension ID Pasirinktinis plėtinio ID - - Due to Snap sandboxing, you must run a script to enable browser integration.<br />You can obtain this script from %1 - Dėl Snap smėlio dėžės reikia paleisti skriptą, kad būtų įjungti naršyklės integraciją.<br />Šį skriptą galite gauti iš %1 - - - KeePassXC-Browser is needed for the browser integration to work. <br />Download it for %1 and %2 and %3. %4 - KeePassXC-Browser reikalinga, kad naršyklės integracija veiktų. <br />Atsisiųskite jį %1, %2 ir %3. %4 - - - Please see special instructions for browser extension use below - Toliau skaitykite specialius naršyklės plėtinio naudojimo nurodymus - Executable Files Vykdomieji failai @@ -1233,7 +1270,7 @@ Do you want to overwrite the passkey in %1 - %2? <b>Warning:</b> Only adjust these settings if necessary. - + <b>Įspėjimas:</b> Derinkite šiuos nustatymus tik tuo atveju, jei to reikia. The custom proxy location does not exist. @@ -1255,6 +1292,14 @@ Do you want to overwrite the passkey in %1 - %2? Allow using localhost with passkeys + + KeePassXC-Browser is needed for the browser integration to work. <br />Download it for %1 and %2 and %3. + + + + Browsers installed using Snap or Flatpak are not supported with exception to Firefox installed using Snap. + + CloneDialog @@ -1391,12 +1436,25 @@ Do you want to overwrite the passkey in %1 - %2? Failed to parse CSV file: %1 - + Nepavyko išnagrinėti CSV failo: %1 Imported from CSV file: %1 + Importuota iš CSV failo: %1 + + + No Title Selected + + No title column was selected, entries will be hard to tell apart. +Are you sure you want to import? + + + + Tags + Žymos + CsvParserModel @@ -1460,6 +1518,14 @@ Atsarginė duomenų bazė, esanti %2 Recycle Bin Šiukšlinė + + Database file read error. + + + + No file path was provided. + + DatabaseOpenDialog @@ -1608,21 +1674,13 @@ Kad ši klaida nepasirodytų, turite eiti į "Duomenų bazės nustatymai / <p>In addition to a password, you can use a secret file to enhance the security of your database. This file can be generated in your database's security settings.</p><p>This is <strong>not</strong> your *.kdbx database file!</p> - - Click to add a key file. - - - - <a href="#" style="text-decoration: underline">I have a key file</a> - - Use hardware key [Serial: %1] Use hardware key - + Naudoti aparatinės įrangos raktą Your database file is NOT a key file! @@ -1648,6 +1706,18 @@ Are you sure you want to continue with this file?. Refresh Hardware Keys + + Click to add a key file. + Spustelėkite norėdami pridėti rakto failą. + + + <a href="#" style="text-decoration: underline">I have a key file</a> + <a href="#" style="text-decoration: underline">Aš turiu rakto failą</a> + + + Hardware keys found, but no slots are configured. + + DatabaseSettingWidgetMetaData @@ -1682,6 +1752,22 @@ Are you sure you want to continue with this file?. Maintenance Priežiūra + + KeeShare + + + + Secret Service Integration + + + + Remote Sync + + + + Database Settings: %1 + Duomenų bazės nustatymai: %1 + DatabaseSettingsWidgetBrowser @@ -1795,7 +1881,7 @@ Tai būtina tik tuo atveju, jei jūsų duomenų bazė yra kito kopija ir naršyk No keys found - + Nerasta jokių raktų Removed keys from database @@ -1853,11 +1939,11 @@ Ar tikrai norite tęsti darbą be slaptažodžio? Silpnas slaptažodis - You must enter a stronger password to protect your database. + This is a weak password! For better protection of your secrets, you should choose a stronger password. - This is a weak password! For better protection of your secrets, you should choose a stronger password. + The provided password does not meet the minimum quality requirement. @@ -2001,7 +2087,7 @@ Jei išlaikysite šį numerį, jūsų duomenų bazė nebus apsaugota nuo brutali Encryption Settings: - + Šifravimo nustatymai: Basic @@ -2152,6 +2238,50 @@ removed from the database. Autosave delay since last change checkbox + + Public Database Metadata + + + + Warning: the following settings are not encrypted. + + + + Display name: + + + + Publically visible display name used on the unlock dialog + + + + Database public display name + + + + Display color: + + + + Publically visible color used on the unlock dialog + + + + Database public display color chooser + + + + Clear + Išvalyti + + + Display icon: + + + + Select Database Icon + + DatabaseSettingsWidgetKeeShare @@ -2247,6 +2377,129 @@ removed from the database. Duomenų bazės aprašymo laukas + + DatabaseSettingsWidgetRemote + + Sync Commands + + + + Remove + Šalinti + + + Command Settings + + + + Name + Pavadinimas + + + Save + Įrašyti + + + Download + Atsisiųsti + + + Command: + Komanda: + + + Download command field + + + + e.g.: "sftp user@hostname" or "scp user@hostname:DatabaseOnRemote.kdbx {TEMP_DATABASE}" + + + + Input: + + + + Download input field + + + + Upload + + + + Upload command field + + + + e.g.: "sftp user@hostname" or "scp {TEMP_DATABASE} user@hostname:DatabaseOnRemote.kdbx" + + + + Upload input field + + + + Name cannot be empty. + + + + Test + Išbandyti + + + Download command cannot be empty. + Atsiuntimo komanda negali būti tuščia. + + + Download failed with error: %1 + + + + Download finished, but file %1 could not be found. + + + + Download successful. + Atsiuntimas sėkmingas. + + + Save Remote Settings + + + + You have unsaved changes. Do you want to save them? + + + + e.g.: +get DatabaseOnRemote.kdbx {TEMP_DATABASE} +exit +--- +{TEMP_DATABASE} is used as placeholder to store the database in a temporary location +The command has to exit. In case of `sftp` as last command `exit` has to be sent + + + + + e.g.: +put {TEMP_DATABASE} DatabaseOnRemote.kdbx +exit +--- +{TEMP_DATABASE} is used as placeholder to store the database in a temporary location +The command has to exit. In case of `sftp` as last command `exit` has to be sent + + + + + Timeout: + + + + seconds + sekundžių + + DatabaseTabWidget @@ -2320,6 +2573,11 @@ Tai tikrai klaida, praneškite apie tai kūrėjams. Database tab name modifier %1 [Užrakinta] + + %1 [Temporary] + Database tab name modifier + + DatabaseWidget @@ -2443,26 +2701,6 @@ Išsaugoti pakeitimus? File has changed Failas pasikeitė - - The database file has changed. Do you want to load the changes? - Duomenų bazės failas pasikeitė. Ar norite įkelti pakeitimus? - - - Merge Request - Suliejimo užklausa - - - The database file has changed and you have unsaved changes. -Do you want to merge your changes? - Duomenų bazės failas pasikeitė ir jūs turite neįrašytų pakeitimų. -Ar norite sulieti savo pakeitimus? - - - Could not open the new database file while attempting to autoreload. -Error: %1 - Nepavyko atidaryti naujos duomenų bazės failo bandant automatiškai įkelti. -Klaida: %1 - Disable safe saves? Išjungti saugų išsaugojimą? @@ -2514,6 +2752,86 @@ Išjunkite saugų išsaugojimą ir bandykite dar kartą? Database tab name modifier %1 [Nauja duomenų bazė] + + Remote Sync did not contain any download or upload commands. + + + + Remote sync '%1' completed successfully! + + + + Remote sync '%1' failed: %2 + + + + Error while saving database %1: %2 + Klaida įrašant duomenų bazę %1: %2 + + + Downloading... + Atsiunčiama... + + + Uploading... + + + + Syncing... + Sinchronizuojama... + + + Remove passkey from entry + + + + Do you want to remove the passkey from this entry? + + + + The database file "%1" was modified externally + + + + Do you want to load the changes? + + + + Reload database + + + + Reloading database… + + + + Reload canceled + + + + Reload successful + + + + Reload pending user action… + + + + The database file "%1" was modified externally.<br>How would you like to proceed?<br><br>Merge all changes<br>Ignore the changes on disk until save<br>Discard unsaved changes + + + + The database file "%1" was modified externally.<br>How would you like to proceed?<br><br>Merge all changes then save<br>Overwrite the changes on disk<br>Discard unsaved changes + + + + Database file overwritten. + + + + Database file on disk cannot be unlocked with current credentials.<br>Enter new credentials and/or present hardware key to continue. + + EditEntryWidget @@ -2565,10 +2883,6 @@ Išjunkite saugų išsaugojimą ir bandykite dar kartą? n/a nėra - - (encrypted) - (šifruota) - Select private key Pasirinkti privatųjį raktą @@ -2671,6 +2985,10 @@ Ar norėtumėte ją ištaisyti? %n year(s) %n metai (-ai)%n metai (-ai)%n metai (-ai)%n metai (-ai) + + Failed to decrypt SSH key, ensure password is correct. + + EditEntryWidgetAdvanced @@ -2842,18 +3160,10 @@ Ar norėtumėte ją ištaisyti? Skip Auto-Submit for this entry Praleisti šio įrašo automatinį pateikimą - - Only send this setting to the browser for HTTP Auth dialogs. If enabled, normal login forms will not show this entry for selection. - Siųskite šį parametrą tik į naršyklę HTTP Auth dialogo langams. Jei įjungta, įprastose prisijungimo formose šis pasirinkimo įrašas nebus rodomas. - Use this entry only with HTTP Basic Auth Naudokite šį įrašą tik su HTTP Basic Auth - - Do not send this setting to the browser for HTTP Auth dialogs. If enabled, HTTP Auth dialogs will not show this entry for selection. - Nesiųskite šio parametro į naršyklę HTTP Auth dialogams. Jei įjungta, HTTP Auth dialogo languose šis pasirinkimo įrašas nebus rodomas. - Do not use this entry with HTTP Basic Auth Nenaudokite šio įrašo su HTTP Basic Auth @@ -2878,6 +3188,14 @@ Ar norėtumėte ją ištaisyti? Additional URLs + + Only send this entry to the browser for HTTP Auth dialogs. If enabled, normal login forms will not show this entry for selection. + + + + Do not send this entry to the browser for HTTP Auth dialogs. If enabled, HTTP Auth dialogs will not show this entry for selection. + + EditEntryWidgetHistory @@ -2974,7 +3292,7 @@ Ar norėtumėte ją ištaisyti? &Username: - + Na&udotojo vardas: &Title: @@ -2982,11 +3300,11 @@ Ar norėtumėte ją ištaisyti? &Password: - + Sla&ptažodis: UR&L: - + UR&L: &Notes: @@ -2998,11 +3316,11 @@ Ar norėtumėte ją ištaisyti? T&ags: - + Ž&ymės: &Expires: - + Ba&igia galioti: @@ -3100,6 +3418,10 @@ Ar norėtumėte ją ištaisyti? seconds sekundžių + + Clear agent + + EditGroupWidget @@ -3542,6 +3864,24 @@ Dėl to gali sutrikti paveiktų papildinių veikimas. %1 - Clone %1 - Klonas + + Passkey + + + + Invalid conversion type: %1 + Netinkamas vertimo tipas: %1 + + + Invalid conversion syntax: %1 + Netinkama vertimo sintaksė: %1 + + + Invalid regular expression syntax %1 +%2 + Netinkama regexp sintaksė %1 + + EntryAttachments @@ -3550,6 +3890,21 @@ Dėl to gali sutrikti paveiktų papildinių veikimas. Nepavyko atidaryti failo "%1" + + EntryAttachmentsDialog + + Form + Forma + + + File name + Failo pavadinimas + + + File contents... + Failo turinys... + + EntryAttachmentsModel @@ -3587,14 +3942,6 @@ Dėl to gali sutrikti paveiktų papildinių veikimas. Remove Šalinti - - Rename selected attachment - Pervadinti pasirinktą priedą - - - Rename - Pervadinti - Open selected attachment Atverti pasirinktą priedą @@ -3712,6 +4059,18 @@ Would you like to overwrite the existing attachment? Priedas "%1" jau egzistuoja. Ar norite perrašyti esamą priedą? + + New + Naujas + + + Preview + Peržiūra + + + Failed to preview an attachment: Attachment not found + Nepavyko peržiūrėti priedo: Priedas nerastas + EntryAttributesModel @@ -3908,7 +4267,11 @@ Ar norite perrašyti esamą priedą? Background Color - + Fono spalva + + + Group Path + Grupės kelias @@ -4015,7 +4378,7 @@ Ar norite perrašyti esamą priedą? Double click to copy to clipboard - + Spustelėkite du raktus norėdami nukopijuoti į iškarpinę @@ -4271,7 +4634,7 @@ DuckDuckGo svetainės piktogramų paslaugą galite įjungti programos nustatymų ImportWizard Import Wizard - + Importavimo vediklis @@ -4304,6 +4667,14 @@ DuckDuckGo svetainės piktogramų paslaugą galite įjungti programos nustatymų Url + + Could not load key file. + Nepavyko įkelti rakto failo. + + + Could not open remote database. Password or key file may be incorrect. + + ImportWizardPageSelect @@ -4329,7 +4700,7 @@ DuckDuckGo svetainės piktogramų paslaugą galite įjungti programos nustatymų Import Into: - + Importuoti į: New Database @@ -4361,7 +4732,7 @@ DuckDuckGo svetainės piktogramų paslaugą galite įjungti programos nustatymų Bitwarden (.json) - + Bitwarden (.json) KeePass 1 Database (.kdb) @@ -4407,6 +4778,44 @@ DuckDuckGo svetainės piktogramų paslaugą galite įjungti programos nustatymų KeePass1 Database + + Proton Pass (.json) + + + + Proton Pass JSON Export + + + + Temporary Database + Laikina duomenų bazė + + + Command: + Komanda: + + + e.g.: "sftp user@hostname" or "scp user@hostname:DatabaseOnRemote.kdbx {TEMP_DATABASE}" + + + + Input: + + + + e.g.: +get DatabaseOnRemote.kdbx {TEMP_DATABASE} +exit +--- +{TEMP_DATABASE} is used as placeholder to store the database in a temporary location +The command has to exit. In case of `sftp` as last commend `exit` has to be sent + + + + + Remote Database (.kdbx) + + KMessageWidget @@ -5492,7 +5901,7 @@ Ar tikrai norite tęsti darbą su šiuo failu? Show Menubar - + Rodyti meniu juostą Show Toolbar @@ -5547,12 +5956,6 @@ Egzistuoja didelė pažeidimų rizika, turėkite atsarginę duomenų bazių kopi Expect some bugs and minor issues, this version is meant for testing purposes. PASTABA: Jūs naudojate ankstyvąją KeePassXC versiją. Tikėkitės klaidų ir nedidelių problemų, ši versija skirta testavimo tikslams. - - - WARNING: Your Qt version may cause KeePassXC to crash with an On-Screen Keyboard. -We recommend you use the AppImage available on our downloads page. - ĮSPĖJIMAS: Dėl jūsų Qt versijos "KeePassXC" gali sugesti naudojant ekrano klaviatūrą. -Rekomenduojame naudoti "AppImage", pasiekiamą mūsų atsisiuntimų puslapyje. No Tags @@ -5616,7 +6019,7 @@ Rekomenduojame naudoti "AppImage", pasiekiamą mūsų atsisiuntimų pu Import… - + Importuoti… Passkeys… @@ -5626,6 +6029,10 @@ Rekomenduojame naudoti "AppImage", pasiekiamą mūsų atsisiuntimų pu Import Passkey + + Remote S&ync… + + Quit Application @@ -5636,11 +6043,11 @@ Rekomenduojame naudoti "AppImage", pasiekiamą mūsų atsisiuntimų pu Open Database - + Atverti duomenų bazę Create Database - + Sukurti duomenų bazę Merge From Database @@ -5648,7 +6055,7 @@ Rekomenduojame naudoti "AppImage", pasiekiamą mūsų atsisiuntimų pu Create Entry - + Sukurti įrašą Edit Entry @@ -5656,11 +6063,11 @@ Rekomenduojame naudoti "AppImage", pasiekiamą mūsų atsisiuntimų pu Delete Entry - + Ištrinti įrašą Create Group - + Sukurti grupę Edit Group @@ -5668,7 +6075,7 @@ Rekomenduojame naudoti "AppImage", pasiekiamą mūsų atsisiuntimų pu Delete Group - + Ištrinti grupę Download All Favicons @@ -5708,11 +6115,11 @@ Rekomenduojame naudoti "AppImage", pasiekiamą mūsų atsisiuntimų pu Move Entry Up - + Pakelti įrašą Move Entry Down - + Nuleisti įrašą Copy Username @@ -5730,6 +6137,10 @@ Rekomenduojame naudoti "AppImage", pasiekiamą mūsų atsisiuntimų pu Show Password Generator + + Remove Passkey From Entry + + Perform Auto-Type: {USERNAME} @@ -5756,7 +6167,7 @@ Rekomenduojame naudoti "AppImage", pasiekiamą mūsų atsisiuntimų pu Copy URL - + Kopijuoti URL Copy Notes @@ -5764,11 +6175,11 @@ Rekomenduojame naudoti "AppImage", pasiekiamą mūsų atsisiuntimų pu Export to CSV - + Eksportuoti į CSV Export to HTML - + Eksportuoti į HTML Import KeePass1 Database @@ -5780,7 +6191,7 @@ Rekomenduojame naudoti "AppImage", pasiekiamą mūsų atsisiuntimų pu Import CSV File - + Importuoti CSV failą Show TOTP QR Code @@ -5868,12 +6279,40 @@ Rekomenduojame naudoti "AppImage", pasiekiamą mūsų atsisiuntimų pu Export to XML - + Eksportuoti į XML Toggle Allow Screen Capture + + Show Group Panel + + + + Toggle Show Group Panel + + + + Setup Remote Sync… + + + + Password Generator + Slaptažodžių generatorius + + + E&xpire Entry… + + + + Clear SSH Agent + + + + Clear all identities in ssh-agent + + ManageDatabase @@ -6024,6 +6463,25 @@ Rekomenduojame naudoti "AppImage", pasiekiamą mūsų atsisiuntimų pu Užpildykite rodomą pavadinimą ir pasirinktinį naujos duomenų bazės aprašymą: + + NewEntryAttachmentsDialog + + Attachment name cannot be empty + + + + Attachment with the same name already exists + + + + Save attachment + Įrašyti priedą + + + New entry attachment + + + NixUtils @@ -6211,6 +6669,10 @@ Rekomenduojame naudoti "AppImage", pasiekiamą mūsų atsisiuntimų pu Unexpected EOF when writing private key Netikėta failo pabaiga, rašant privatųjį raktą + + (encrypted) + (šifruota) + OpenSSHKeyGenDialog @@ -6276,15 +6738,15 @@ Do you want to overwrite it? Cannot open file - + Nepavyksta atverti fail Cannot open file "%1" for writing. - + Nepavyksta atverti failo „%1“ rašymui Cannot write to file - + Nepavyksta rašyti į failą @@ -6295,7 +6757,7 @@ Do you want to overwrite it? Username: %1 - + Naudotojo vardas: %1 Group @@ -6323,7 +6785,7 @@ Do you want to overwrite it? Create new entry - + Sukurti naują įrašą Relying Party: %1 @@ -6354,11 +6816,11 @@ Do you want to overwrite it? Cannot open file - + Nepavyksta atverti fail Cannot open file "%1" for reading. - + Nepavyko atverti failo „%1“ skaitymui. Open passkey file @@ -6561,10 +7023,6 @@ The following data is missing: Also choose from: Taip pat pasirinkti iš: - - Excluded characters: "0", "1", "l", "I", "O", "|", "﹒" - Neįtraukti simboliai: "0", "1", "l", "I", "O", "|", "﹒". - Exclude look-alike characters Pašalinti panašiai atrodančius simbolius @@ -6589,10 +7047,6 @@ The following data is missing: Word Count: Žodžių skaičius: - - Character Count: - Simbolių skaičius: - Word Case: Žodžio atvejis: @@ -6605,10 +7059,6 @@ The following data is missing: Add custom wordlist Pridėti pasirinktinį žodžių sąrašą - - character - simbolis - Close Užverti @@ -6715,6 +7165,22 @@ Ar norite jį perrašyti? Special Characters Specialūs simboliai + + passwordLength + + + + Characters: %1 + + + + MIXED case + + + + Excluded characters: "0", "1", "l", "I", "O", "|", "﹒", "B", "8", "G", "6" + + PasswordWidget @@ -6782,6 +7248,21 @@ Ar norite jį perrašyti? Paspauskite ir tabuliuokite tarp simbolių + + PreviewEntryAttachmentsDialog + + Preview entry attachment + + + + No preview available + + + + Image format not supported + + + QMessageBox @@ -6822,7 +7303,7 @@ Ar norite jį perrašyti? Continue with weak password - + Tęsti naudojant silpną slaptažodį @@ -7460,10 +7941,6 @@ Ar norite jį perrašyti? Invalid word count %1 Neteisingas žodžių skaičius %1 - - The word list is too small (< 1000 items) - Žodžių sąrašas per mažas (< 1000 items) - Title for the entry. Įrašo pavadinimas. @@ -7608,10 +8085,6 @@ Ar norite jį perrašyti? Exit interactive mode. Išeikite iš interaktyvaus režimo. - - Format to use when exporting. Available choices are 'xml' or 'csv'. Defaults to 'xml'. - Formatas, kurį naudoti eksportuojant. Galima pasirinkti 'xml' arba 'csv'. Numatytasis yra 'xml'. - Exports the content of a database to standard output in the specified format. Eksportuoja duomenų bazės turinį į standartinę išvestį nurodytu formatu. @@ -8199,18 +8672,6 @@ Branduolys: %3 %4 file empty failas tuščias - - malformed string - netaisyklinga eilutė - - - missing closing quote - trūksta užveriamosios kabutės - - - %1: (row, col) %2,%3 - %1: (eil., stulp.) %2,%3 - AES 256-bit AES 256 bitų @@ -8458,7 +8919,7 @@ This option is deprecated, use --set-key-file instead. Databases have been locked. - + Duomenų bazės užrakintos. Attestation not supported @@ -8579,11 +9040,11 @@ This option is deprecated, use --set-key-file instead. File does not exist. - + Failo nėra. Cannot open file: %1 - + Nepavyksta atverti failo: %1 Cannot parse file: %1 at position %2 @@ -8603,7 +9064,7 @@ This option is deprecated, use --set-key-file instead. Wrong password - + Neteisingas slaptažodis Invalid encrypted data field @@ -8615,11 +9076,11 @@ This option is deprecated, use --set-key-file instead. Cannot initialize cipher - + Nepavyksta inicijuoti šifro Cannot decrypt data - + Nepavyksta iššifruoti duomenų Bitwarden Import @@ -8655,13 +9116,89 @@ This option is deprecated, use --set-key-file instead. - Unsupported KDF type, cannot decrypt json file + Unknown passkeys error - Unknown passkeys error + Invalid KDF iterations, cannot decrypt json file + + Unsupported format, ensure your Bitwarden export is password-protected + + + + Only PBKDF and Argon2 are supported, cannot decrypt json file + + + + Reset Shortcuts + + + + Double click an action to change its shortcut + + + + Filter... + + + + Shortcut Conflict + + + + Shortcut %1 conflicts with '%2'. Overwrite shortcut? + + + + Cannot generate valid passphrases because the wordlist is too short + + + + Encrypted files are not supported. + + + + Proton Pass Import + + + + Delete plugin data? + Ištrinti papildinių duomenis? + + + Delete plugin data from Entry(s)? + + + + Passkey + + + + Format to use when exporting. Available choices are 'xml', 'csv' or 'html'. Defaults to 'xml'. + + + + start minimized to the system tray + + + + malformed string, possible unescaped delimiter + + + + missing closing delimiter + + + + %1, row: %2, column: %3 + + + + Tags + Žymos + QtIOCompressor @@ -8697,6 +9234,37 @@ This option is deprecated, use --set-key-file instead. Vidinė zlib klaida: + + RemoteHandler + + Command `%1` did not finish in time. Process was killed. + + + + Failed to upload merged database. Command `%1` did not finish in time. Process was killed. + + + + Invalid download parameters provided. + + + + Command `%1` failed to download database. + + + + Invalid database pointer or upload parameters provided. + + + + Command `%1` exited with status code: %2 + + + + Failed to upload merged database. Command `%1` exited with status code: %2 + + + ReportsWidgetBrowserStatistics @@ -8763,6 +9331,10 @@ This option is deprecated, use --set-key-file instead. Exclude from reports Neįtraukti į ataskaitas + + Expire Entry(s)… + + Only show entries that have a URL @@ -8773,42 +9345,39 @@ This option is deprecated, use --set-key-file instead. Show expired entries - + Rodyti nebegaliojančius įrašus (Expired) - + (Nebegalioja) + + + Delete plugin data from Entry(s)… + ReportsWidgetHealthcheck - Hover over reason to show additional details. Double-click entries to edit. - Užveskite pelės žymeklį virš priežasties, kad parodytumėte papildomą informaciją. Dukart spustelėkite įrašus, kuriuos norite redaguoti. + Show expired entries + Rodyti nebegaliojančius įrašus - Bad - Password quality - Blogas + (Expired) + (Nebegalioja) + + + Hover over reason to show additional details. Double-click entries to edit. + Užveskite pelės žymeklį virš priežasties, kad parodytumėte papildomą informaciją. Dukart spustelėkite įrašus, kuriuos norite redaguoti. Bad — password must be changed Blogas - slaptažodis turi būti pakeistas - - Poor - Password quality - Blogas - Poor — password should be changed Prastas — slaptažodis turėtų būti pakeistas - - Weak - Password quality - Silpnas - Weak — consider changing the password Silpnas — apsvarstykite galimybę pakeisti slaptažodį @@ -8857,18 +9426,14 @@ This option is deprecated, use --set-key-file instead. Exclude from reports Neįtraukti į ataskaitas - - Show expired entries - + + Expire Entry(s)… + Show entries that have been excluded from reports - - (Expired) - - ReportsWidgetHibp @@ -8964,6 +9529,10 @@ This option is deprecated, use --set-key-file instead. Exclude from reports Neįtraukti į ataskaitas + + Expire Entry(s)… + + ReportsWidgetPasskeys @@ -9009,11 +9578,11 @@ This option is deprecated, use --set-key-file instead. Show expired entries - + Rodyti nebegaliojančius įrašus (Expired) - + (Nebegalioja) Export Confirmation @@ -9205,6 +9774,14 @@ This option is deprecated, use --set-key-file instead. No agent running, cannot list identities. Joks agentas neveikia, negali išvardyti tapatybių. + + Failed to remove all SSH identities from agent. + + + + All SSH identities removed from agent. + + SearchHelpWidget @@ -9490,29 +10067,6 @@ This option is deprecated, use --set-key-file instead. Eksportas į %1 - - ShortcutSettingsWidget - - Double click an action to change its shortcut - - - - Shortcut Conflict - - - - Filter... - - - - Shortcut %1 conflicts with '%2'. Overwrite shortcut? - - - - Reset Shortcuts - - - TagModel @@ -9722,15 +10276,15 @@ Pavyzdys: JBSWY3DPEHPK3PXP Create Database - + Sukurti duomenų bazę Open Database - + Atverti duomenų bazę Import File - + Importuoti failą @@ -9802,11 +10356,15 @@ Pavyzdys: JBSWY3DPEHPK3PXP Neaptikti jokie aparatūros raktai - <p>If you own a <a href="https://www.yubico.com/">YubiKey</a> or <a href="https://onlykey.io">OnlyKey</a>, you can use it for additional security.</p><p>The key requires one of its slots to be programmed as <a href="https://docs.yubico.com/yesdk/users-manual/application-otp/challenge-response.html">HMAC-SHA1 Challenge-Response</a>.</p> + Refresh hardware keys + Iš naujo įkelti aparatinės įrangos raktus + + + <p>If you own a <a href="https://www.yubico.com/">YubiKey</a> or <a href="https://onlykey.io">OnlyKey</a>, you can use it for additional security.</p><p>The key requires one of its slots to be programmed with <a href="https://keepassxc.org/docs/#faq-yubikey-howto">Challenge-Response</a>.</p> - Refresh hardware keys + Hardware keys found, but no slots are configured diff --git a/share/translations/keepassxc_my.ts b/share/translations/keepassxc_my.ts index 61cfab8c4..ca342676f 100644 --- a/share/translations/keepassxc_my.ts +++ b/share/translations/keepassxc_my.ts @@ -217,18 +217,50 @@ You must restart the application to set the new language. Would you like to restart now? ဘာသာစကားသစ် သတ်မှတ်ရန် အက်ပလီကေးရှင်းကို ပြန်လည်စတင်ရပါမည်။ ယခု ပြန်စလိုပါသလား။ - - Reset Settings? - ဆက်တင်များကို ပြန်လည်သတ်မှတ်မလား။ - - - Are you sure you want to reset all general and security settings to default? - ယေဘုယျနှင့် လုံခြုံရေး ဆက်တင်အားလုံးကို ပုံသေမူလအဖြစ် ပြန်လည်သတ်မှတ်လိုသည်မှာ သေချာပါသလား။ - Select backup storage directory အရံသိမ်းဖိုင်ကို သိမ်းမည့် နေရာရွေးပါ။ + + Confirm Reset + + + + Are you sure you want to reset all settings to default? + + + + Import KeePassXC Settings + + + + Failed to import settings from %1, not a valid settings file. + + + + Export KeePassXC Settings + + + + Small + + + + Normal + + + + Medium + + + + Large + + + + Custom + + ApplicationSettingsWidgetGeneral @@ -280,25 +312,6 @@ Include beta releases when checking for updates အပ်ဒိတ်များကို စစ်ဆေးချိန်တွင် အစမ်းသုံး ထုတ်လုပ်မှုများ ပါဝင်ပါစေ - - On database unlock, show entries that - ဒေတာဘေ့စ် ပွင့်နေလျင်, ........... သော ထည့်ပြီးသားအချက်အလက်များကို ပြပါ။ - - - have expired - On database unlock, show entries that... - သက်တမ်းကုန်သွား - - - days - On database unlock, show entries that will expire within %1 days - ရက်များ - - - will expire within - On database unlock, show entries that... - အတွင်းမှာ သက်တမ်းကုန်မည် - File Management ဖိုင်စီမံခန့်ခွဲမှု @@ -323,22 +336,10 @@ Backup database file before saving မသိမ်းမီ ဒေတာဘေ့စ်ဖိုင်ကို အရန်ပြုပါ - - Backup destination - အရံသိမ်းဖိုင် သိမ်းဆည်းရာနေရာ - - - Specifies the database backup file location. Occurrences of "{DB_FILENAME}" are replaced with the filename of the saved database without extension. {TIME:<format>} is replaced with the backup time, see https://doc.qt.io/qt-5/qdatetime.html#toString. <format> defaults to format string "dd_MM_yyyy_hh-mm-ss". - ဒေတာဘေ့စ် အရံသိမ်းဖိုင်ကို သိမ်းရန်နေရာ သတ်မှတ်ပြီးဖြစ်သည်။ "{DB_FILENAME}" များကို တွေ့ရှိပါက ၄င်းတို့ကို ဖိုင်နာမည်ဖြင့် အစားထိုးသွားမည်ဖြစ်သည်။ {TIME: 1} ကို အရံသိမ်းဖိုင် သိမ်းရန်ကြာချိန် ဖြင့် အစားထိုးမည်။ https://doc.qt.io/qt-5/qdatetime.html#toString တွင်ကြည့်ပါ။ ရက်စွဲ နဂိုထည့်သွင်းပြီး ဖောမတ်မှာ "dd_MM_yyyy_hh-mm-ss" ဖြစ်သည်။ - {DB_FILENAME}.old.kdbx [DB_FILENAME].old.kdbx - - Choose... - ရွေးချယ်ပါ - Use alternative saving method (may solve problems with Dropbox, Google Drive, GVFS, etc.) အခြားရွေးချယ်နိုင်သော သိမ်းဆည်းသည့်နည်းလမ်းကို သုံးပါ (Dropbox၊ Google Drive၊ GVFS စသည်တို့ဖြင့် ပြဿနာများကို ဖြေရှင်းနိုင်ပါမည်) @@ -505,6 +506,71 @@ Remember last typed entry for: နောက်ဆုံးရိုက်ထည့်ခဲ့သော ထည့်သွင်းချက်ကိုမှတ်ထားပါ + + On database unlock, show entries that will expire within + + + + On database unlock, show entries that will expire within + + + + days + number of days warning for password expiration + ရက်များ + + + Destination format: + + + + <html><head/><body><p><span style=" font-weight:600;">{DB_FILENAME}</span> is replaced with the filename of the saved database without extension</p><p><span style=" font-weight:600;">{TIME:&lt;format&gt;}</span> is replaced with the specified time format (default: dd_MM_yyyy_hh-mm-ss)</p><p>See the User Guide for more details</p></body></html> + + + + Choose folder... + + + + Show confirmation before moving entries to recycle bin + + + + Copy data on double clicking field in entry view + + + + Show toolbar + + + + Show the menu bar by pressing the Alt key + + + + Show menubar + + + + Import settings… + + + + Export settings… + + + + Open browser on double clicking URL field in entry view + + + + Font size: + + + + Font size selection + + ApplicationSettingsWidgetSecurity @@ -570,18 +636,6 @@ Hide passwords in the entry preview panel ဖြည့်သွင်းချက် နမူနာ မျက်နှာပြင်ရှိ စကားဝှက်များကို ဝှက်ပါ - - Hide entry notes by default - ဖြည့်သွင်းချက် မှတ်စုများကို ပုံသေ ဝှက်ပါ - - - Move entries to recycle bin without confirmation - ဖြည့်သွင်းချက်များကို အတည်ပြုချက်မလိုဘဲ အမှိုက်ပုံးသို့ ရွှေ့ရန် - - - Enable double click to copy the username/password entry columns - အသုံးပြုသူအမည်/စကားဝှက် ဖြည့်သွင်းချက် ကော်လံများကို ကူးရန် ကလစ်နှစ်ချက်နှိပ်ခြင်းကို ဖွင့်ထားပါ - Privacy ကိုယ်ရေးလုံခြုံမှု @@ -594,6 +648,18 @@ Hide TOTP in the entry preview panel + + Lock databases when switching user + + + + Lock Options + + + + Hide notes in the entry preview panel + + AutoType @@ -641,20 +707,6 @@ Entry does not have attribute for PICKCHARS: %1 ထည့်သွင်းမှုတွင် PICKCHARS အတွက် အရည်အချင်း မရှိပါ - %1 - - Invalid conversion type: %1 - ပြောင်းလဲမှု အမျိုးအစား မမှန်ကန်ပါ - %1 - - - Invalid conversion syntax: %1 - ပြောင်းလဲမှု ဝါကျဖွဲ့စည်းပုံ မမှန်ကန်ပါ - %1 - - - Invalid regular expression syntax %1 -%2 - ပုံမှန်အသုံးအနှုန်း ဝါကျဖွဲ့စည်းပုံ မမှန်ကန်ပါ %1 -%2 - Invalid placeholder: %1 placeholder မမှန်ကန်ပါ - %1 @@ -1022,10 +1074,6 @@ Do you want to overwrite the passkey in %1 - %2? General ယေဘုယျ - - Browsers installed as snaps are currently not supported. - snaps အဖြစ် တပ်ဆင်ထားသော ဘရောက်ဇာများကို လက်ရှိတွင် မပံ့ပိုးပါ။ - Enable integration for these browsers: ဤဘရောက်ဇာများအတွက် ပေါင်းစပ်ထည့်သွင်းမှုကို ဖွင့်ပါ - @@ -1197,18 +1245,6 @@ Do you want to overwrite the passkey in %1 - %2? Custom extension ID စိတ်ကြိုက်အဆက် ID - - Due to Snap sandboxing, you must run a script to enable browser integration.<br />You can obtain this script from %1 - Snap ကုဒ်စမ်းသပ်သည့်နည်းလမ်းအရ သင်သည် ဘရောက်ဇာ ပေါင်းစပ်ထည့်သွင်းမှု ပြုလုပ်ရန် ရိုးရိုးပရိုဂရမ်တစ်ခုကို လည်ပတ်ရပါမည်။ <br /> သင်သည် ဤရိုးရိုးပရိုဂရမ်ကို %1 မှ ရယူနိုင်သည် - - - KeePassXC-Browser is needed for the browser integration to work. <br />Download it for %1 and %2 and %3. %4 - ဘရောက်ဇာ ပေါင်းစပ်ထည့်သွင်းမှု အလုပ်လုပ်ရန်အတွက် KeePassXC-ဘရောက်ဇာ လိုအပ်သည်။ <br />%1 နှင့် %2 နှင့် %3 အတွက် ၎င်းကို ဒေါင်းလုဒ်လုပ်ပါ။ %4 - - - Please see special instructions for browser extension use below - ကျေးဇူးပြု၍ ဘရောက်ဇာအဆက် သုံးရန် အထူးညွှန်ကြားချက်များကို အောက်တွင်ကြည့်ပါ - Executable Files လည်ပတ်လုပ်ဆောင်နိုင်သော ဖိုင်များ @@ -1257,6 +1293,14 @@ Do you want to overwrite the passkey in %1 - %2? Allow using localhost with passkeys + + KeePassXC-Browser is needed for the browser integration to work. <br />Download it for %1 and %2 and %3. + + + + Browsers installed using Snap or Flatpak are not supported with exception to Firefox installed using Snap. + + CloneDialog @@ -1399,6 +1443,19 @@ Do you want to overwrite the passkey in %1 - %2? Imported from CSV file: %1 + + No Title Selected + + + + No title column was selected, entries will be hard to tell apart. +Are you sure you want to import? + + + + Tags + ပူးတွဲမှုများ + CsvParserModel @@ -1462,6 +1519,14 @@ Backup database located at %2 Recycle Bin အမှိုက်ပုံး + + Database file read error. + + + + No file path was provided. + + DatabaseOpenDialog @@ -1604,14 +1669,6 @@ To prevent this error from appearing, you must go to "Database Settings / S <p>In addition to a password, you can use a secret file to enhance the security of your database. This file can be generated in your database's security settings.</p><p>This is <strong>not</strong> your *.kdbx database file!</p> - - Click to add a key file. - - - - <a href="#" style="text-decoration: underline">I have a key file</a> - - Use hardware key [Serial: %1] @@ -1644,6 +1701,18 @@ Are you sure you want to continue with this file?. Refresh Hardware Keys + + Click to add a key file. + + + + <a href="#" style="text-decoration: underline">I have a key file</a> + + + + Hardware keys found, but no slots are configured. + + DatabaseSettingWidgetMetaData @@ -1678,6 +1747,22 @@ Are you sure you want to continue with this file?. Maintenance ပြုပြင်ထိန်းသိမ်းမှု + + KeeShare + KeeShare + + + Secret Service Integration + လျှို့ဝှက်ဝန်ဆောင်မှု ပေါင်းစပ်ထည့်သွင်းခြင်း + + + Remote Sync + + + + Database Settings: %1 + + DatabaseSettingsWidgetBrowser @@ -1849,11 +1934,11 @@ Are you sure you want to continue without a password? အားနည်းသော စကားဝှက် - You must enter a stronger password to protect your database. + This is a weak password! For better protection of your secrets, you should choose a stronger password. - This is a weak password! For better protection of your secrets, you should choose a stronger password. + The provided password does not meet the minimum quality requirement. @@ -2148,6 +2233,50 @@ removed from the database. Autosave delay since last change checkbox + + Public Database Metadata + + + + Warning: the following settings are not encrypted. + + + + Display name: + + + + Publically visible display name used on the unlock dialog + + + + Database public display name + + + + Display color: + + + + Publically visible color used on the unlock dialog + + + + Database public display color chooser + + + + Clear + ရှင်းလင်းရန် + + + Display icon: + + + + Select Database Icon + + DatabaseSettingsWidgetKeeShare @@ -2243,6 +2372,129 @@ removed from the database. ဒေတာဘေ့စ် ဖော်ပြချက် အကွက် + + DatabaseSettingsWidgetRemote + + Sync Commands + + + + Remove + ဖယ်ရှားရန် + + + Command Settings + + + + Name + အမည် + + + Save + သိမ်းရန် + + + Download + + + + Command: + + + + Download command field + + + + e.g.: "sftp user@hostname" or "scp user@hostname:DatabaseOnRemote.kdbx {TEMP_DATABASE}" + + + + Input: + + + + Download input field + + + + Upload + + + + Upload command field + + + + e.g.: "sftp user@hostname" or "scp {TEMP_DATABASE} user@hostname:DatabaseOnRemote.kdbx" + + + + Upload input field + + + + Name cannot be empty. + + + + Test + + + + Download command cannot be empty. + + + + Download failed with error: %1 + + + + Download finished, but file %1 could not be found. + + + + Download successful. + + + + Save Remote Settings + + + + You have unsaved changes. Do you want to save them? + + + + e.g.: +get DatabaseOnRemote.kdbx {TEMP_DATABASE} +exit +--- +{TEMP_DATABASE} is used as placeholder to store the database in a temporary location +The command has to exit. In case of `sftp` as last command `exit` has to be sent + + + + + e.g.: +put {TEMP_DATABASE} DatabaseOnRemote.kdbx +exit +--- +{TEMP_DATABASE} is used as placeholder to store the database in a temporary location +The command has to exit. In case of `sftp` as last command `exit` has to be sent + + + + + Timeout: + + + + seconds + စက္ကန့် + + DatabaseTabWidget @@ -2316,6 +2568,11 @@ This is definitely a bug, please report it to the developers. Database tab name modifier %1 [လော့ချထားသည်] + + %1 [Temporary] + Database tab name modifier + + DatabaseWidget @@ -2439,26 +2696,6 @@ Save changes? File has changed ဖိုင်ကို ပြောင်းလဲပြီးပါပြီ - - The database file has changed. Do you want to load the changes? - ဒေတာဘေ့စ်ဖိုင် ပြောင်းလဲပြီးပါပြီ။ ပြောင်းလဲမှုများကို တင်လိုပါသလား။ - - - Merge Request - ပေါင်းစပ်ရန် တောင်းဆ - - - The database file has changed and you have unsaved changes. -Do you want to merge your changes? - ဒေတာဘေ့စ်ဖိုင် ပြောင်းလဲထားပြီး သင့်တွင် မသိမ်းရသေးသော ပြောင်းလဲမှုများ ရှိသည်။ -သင့်ပြောင်းလဲမှုများကို ပေါင်းစပ်လိုပါသလား။ - - - Could not open the new database file while attempting to autoreload. -Error: %1 - အော်တိုပြန်တင်ရန် ကြိုးစားစဉ် ဒေတာဘေ့စ်ဖိုင်အသစ်ကို ဖွင့်၍မရပါ။ -ပြဿနာ - %1 - Disable safe saves? ဘေးကင်းသော သိမ်းထားမှုများကို ပယ်ဖျက်မလား။ @@ -2510,6 +2747,86 @@ Disable safe saves and try again? Database tab name modifier %1 [ဒေတာဘေ့စ်အသစ်] + + Remote Sync did not contain any download or upload commands. + + + + Remote sync '%1' completed successfully! + + + + Remote sync '%1' failed: %2 + + + + Error while saving database %1: %2 + + + + Downloading... + + + + Uploading... + + + + Syncing... + + + + Remove passkey from entry + + + + Do you want to remove the passkey from this entry? + + + + The database file "%1" was modified externally + + + + Do you want to load the changes? + + + + Reload database + + + + Reloading database… + + + + Reload canceled + + + + Reload successful + + + + Reload pending user action… + + + + The database file "%1" was modified externally.<br>How would you like to proceed?<br><br>Merge all changes<br>Ignore the changes on disk until save<br>Discard unsaved changes + + + + The database file "%1" was modified externally.<br>How would you like to proceed?<br><br>Merge all changes then save<br>Overwrite the changes on disk<br>Discard unsaved changes + + + + Database file overwritten. + + + + Database file on disk cannot be unlocked with current credentials.<br>Enter new credentials and/or present hardware key to continue. + + EditEntryWidget @@ -2561,10 +2878,6 @@ Disable safe saves and try again? n/a မသက်ဆိုင်ပါ - - (encrypted) - (ကုဒ်ဖြင့်ပြောင်းပြီး) - Select private key သီးသန့် စကားဝှက်သော့ကို ရွေးရန် @@ -2667,6 +2980,10 @@ Would you like to correct it? %n year(s) %n နှစ် + + Failed to decrypt SSH key, ensure password is correct. + + EditEntryWidgetAdvanced @@ -2838,18 +3155,10 @@ Would you like to correct it? Skip Auto-Submit for this entry ဤဖြည့်သွင်းချက်အတွက် အလိုအလျောက် တင်သွင်းရန်ကို ကျော်ပါ - - Only send this setting to the browser for HTTP Auth dialogs. If enabled, normal login forms will not show this entry for selection. - ဤဆက်တင်ကို HTTP Auth ဝင်းဒိုးငယ်များအတွက်သာ ဘရောက်ဇာသို့ ပို့ပါ။ ၎င်းကိုဖွင့်ထားစဉ် ပုံမှန် လော့ဂ်အင်ဝင်ရောက်မှု ပုံစံများသည် ဤဖြည့်သွင်းချက်ကို ရွေးချယ်နိုင်ရန် ပြမည်မဟုတ်ပါ။ - Use this entry only with HTTP Basic Auth ဤဖြည့်သွင်းချက်ကို HTTP Basic Auth နှင့်သာ သုံးပါ - - Do not send this setting to the browser for HTTP Auth dialogs. If enabled, HTTP Auth dialogs will not show this entry for selection. - ဤဆက်တင်ကို HTTP Auth ဝင်းဒိုးငယ်များအတွက် ဘရောက်ဇာသို့ မပို့ပါနှင့်။ ၎င်းကိုဖွင့်ထားစဉ် HTTP Auth ဝင်းဒိုးငယ်များသည် ဤဖြည့်သွင်းချက်ကို ရွေးချယ်နိုင်ရန် ပြမည်မဟုတ်ပါ။ - Do not use this entry with HTTP Basic Auth ဤဖြည့်သွင်းချက်ကို HTTP Basic Auth ဖြင့် မသုံးပါနှင့်။ @@ -2874,6 +3183,14 @@ Would you like to correct it? Additional URLs + + Only send this entry to the browser for HTTP Auth dialogs. If enabled, normal login forms will not show this entry for selection. + + + + Do not send this entry to the browser for HTTP Auth dialogs. If enabled, HTTP Auth dialogs will not show this entry for selection. + + EditEntryWidgetHistory @@ -3096,6 +3413,10 @@ Would you like to correct it? seconds စက္ကန့် + + Clear agent + + EditGroupWidget @@ -3538,6 +3859,24 @@ This may cause the affected plugins to malfunction. %1 - Clone %1 - ပုံတူပွားခြင်း + + Passkey + + + + Invalid conversion type: %1 + ပြောင်းလဲမှု အမျိုးအစား မမှန်ကန်ပါ - %1 + + + Invalid conversion syntax: %1 + ပြောင်းလဲမှု ဝါကျဖွဲ့စည်းပုံ မမှန်ကန်ပါ - %1 + + + Invalid regular expression syntax %1 +%2 + ပုံမှန်အသုံးအနှုန်း ဝါကျဖွဲ့စည်းပုံ မမှန်ကန်ပါ %1 +%2 + EntryAttachments @@ -3546,6 +3885,21 @@ This may cause the affected plugins to malfunction. ဖိုင် "%1" ကို မဖွင့်နိုင်ပါ + + EntryAttachmentsDialog + + Form + ပုံစံ + + + File name + + + + File contents... + + + EntryAttachmentsModel @@ -3583,14 +3937,6 @@ This may cause the affected plugins to malfunction. Remove ဖယ်ရှားရန် - - Rename selected attachment - ရွေးချယ်ထားသော ပူးတွဲဖိုင်ကို ပြန်လည်အမည်ပေးရန် - - - Rename - ပြန်လည်အမည်ပေးရန် - Open selected attachment ရွေးချယ်ထားသော ပူးတွဲဖိုင်ကို ဖွင့်ရန် @@ -3705,6 +4051,18 @@ Would you like to overwrite the existing attachment? ဖိုင်တွဲ"%1" ရှိနေပါပြီ။ သင်လက်ရှိဖိုင်တွဲပေါ်တွင် ထပ်ရေးချင်ပါသလား? + + New + + + + Preview + အစမ်းကြည့်ခြင်း + + + Failed to preview an attachment: Attachment not found + + EntryAttributesModel @@ -3903,6 +4261,10 @@ Would you like to overwrite the existing attachment? Background Color + + Group Path + + EntryPreviewWidget @@ -4296,6 +4658,14 @@ You can enable the DuckDuckGo website icon service in the security section of th Url + + Could not load key file. + + + + Could not open remote database. Password or key file may be incorrect. + + ImportWizardPageSelect @@ -4399,6 +4769,44 @@ You can enable the DuckDuckGo website icon service in the security section of th KeePass1 Database + + Proton Pass (.json) + + + + Proton Pass JSON Export + + + + Temporary Database + + + + Command: + + + + e.g.: "sftp user@hostname" or "scp user@hostname:DatabaseOnRemote.kdbx {TEMP_DATABASE}" + + + + Input: + + + + e.g.: +get DatabaseOnRemote.kdbx {TEMP_DATABASE} +exit +--- +{TEMP_DATABASE} is used as placeholder to store the database in a temporary location +The command has to exit. In case of `sftp` as last commend `exit` has to be sent + + + + + Remote Database (.kdbx) + + KMessageWidget @@ -5539,12 +5947,6 @@ This version is not meant for production use. Expect some bugs and minor issues, this version is meant for testing purposes. မှတ်ချက် - သင်သည် KeePassXC မထွက်မီက ဗားရှင်းကို အသုံးပြုနေသည်။ ဤဗားရှင်းကို စမ်းသပ်ရန်အတွက်သာ ရည်ရွယ်သောကြောင့် စက်ချွတ်ယွင်းချက်နှင့် အသေးစား ပြဿနာအချို့ ဖြစ်နိုင်သည်။ - - - WARNING: Your Qt version may cause KeePassXC to crash with an On-Screen Keyboard. -We recommend you use the AppImage available on our downloads page. - သတိပေးချက် - သင်၏ Qt ဗားရှင်းသည် မျက်နှာပြင်ပေါ်ရှိကီးဘုတ် အသုံးပြုပါက KeePassXC ကို ရပ်တန့်စေနိုင်သည်။ -ကျွန်ုပ်တို့၏ ဒေါင်းလုဒ်စာမျက်နှာတွင် ရရှိနိုင်သော AppImage ကို သုံးရန် သင့်အား အကြံပြုပါသည်။ No Tags @@ -5618,6 +6020,10 @@ We recommend you use the AppImage available on our downloads page. Import Passkey + + Remote S&ync… + + Quit Application @@ -5722,6 +6128,10 @@ We recommend you use the AppImage available on our downloads page. Show Password Generator + + Remove Passkey From Entry + + Perform Auto-Type: {USERNAME} @@ -5866,6 +6276,34 @@ We recommend you use the AppImage available on our downloads page. Toggle Allow Screen Capture + + Show Group Panel + + + + Toggle Show Group Panel + + + + Setup Remote Sync… + + + + Password Generator + + + + E&xpire Entry… + + + + Clear SSH Agent + + + + Clear all identities in ssh-agent + + ManageDatabase @@ -6016,6 +6454,25 @@ We recommend you use the AppImage available on our downloads page. ကျေးဇူးပြု၍ သင့်ဒေတာဘေ့စ်အသစ်အတွက် ပြသရန်အမည်နှင့် ရွေးချယ်နိုင်သည့် ဖော်ပြချက်ကို ဖြည့်ပါ။ + + NewEntryAttachmentsDialog + + Attachment name cannot be empty + + + + Attachment with the same name already exists + + + + Save attachment + + + + New entry attachment + + + NixUtils @@ -6203,6 +6660,10 @@ We recommend you use the AppImage available on our downloads page. Unexpected EOF when writing private key သီးသန့်စကားဝှက်သော့ ရေးစဉ် မထင်မှတ်သော EOF ဖြစ်ခဲ့သည် + + (encrypted) + (ကုဒ်ဖြင့်ပြောင်းပြီး) + OpenSSHKeyGenDialog @@ -6553,10 +7014,6 @@ The following data is missing: Also choose from: ၎င်းတို့မှလည်း ရွေးပါ - - - Excluded characters: "0", "1", "l", "I", "O", "|", "﹒" - ဖယ်ထားသော စာလုံးများ - "0"၊ "1"၊ "l"၊ "I"၊ "O"၊ "|"၊ "﹒" - Exclude look-alike characters ဆင်တူစာလုံးများကို ဖယ်ရန် @@ -6581,10 +7038,6 @@ The following data is missing: Word Count: စလုံးအရေအတွက် - - - Character Count: - စာလုံး အရေအတွက် - - Word Case: စကားလုံးအလိုက် - @@ -6597,10 +7050,6 @@ The following data is missing: Add custom wordlist စိတ်ကြိုက်ပြုလုပ်ထားသောစာလုံးစာရင်းအားထည့်သွင်းပါ - - character - စာလုံး - Close ပိတ်ရန် @@ -6707,6 +7156,22 @@ Do you want to overwrite it? Special Characters အထူးစာလုံးများ + + passwordLength + + + + Characters: %1 + + + + MIXED case + + + + Excluded characters: "0", "1", "l", "I", "O", "|", "﹒", "B", "8", "G", "6" + + PasswordWidget @@ -6774,6 +7239,21 @@ Do you want to overwrite it? စာလုံးများကြားတွင် &Tab ကို နှိပ်ပါ + + PreviewEntryAttachmentsDialog + + Preview entry attachment + + + + No preview available + + + + Image format not supported + + + QMessageBox @@ -7452,10 +7932,6 @@ Do you want to overwrite it? Invalid word count %1 မမှန်ကန်သော စာလုံးအရေအတွက် %1 - - The word list is too small (< 1000 items) - စကားလုံးစာရင်း သေးလွန်းသည် (ပါဝင်သည့်အရာ < 1000) - Title for the entry. ဖြည့်သွင်းချက် ခေါင်းစဉ်။ @@ -7600,10 +8076,6 @@ Do you want to overwrite it? Exit interactive mode. ပြန်လှန်တုံ့ပြန်သောမုဒ်မှ ထွက်ပါ။ - - Format to use when exporting. Available choices are 'xml' or 'csv'. Defaults to 'xml'. - ပို့နေစဉ် သုံးရမည့် ဖောမက်။ ရရှိနိုင်သော ရွေးချယ်မှုများမှာ 'xml' သို့မဟုတ် 'csv' ဖြစ်သည်။ 'xml' သည် ပုံသေဖြစ်သည်။ - Exports the content of a database to standard output in the specified format. ဒေတာဘေ့စ်ပါ အကြောင်းအရာကို သတ်မှတ်ဖော်ပြထားသော ဖာမက်ဖြင့် စံရလဒ်အဖြစ် ပို့သည်။ @@ -8191,18 +8663,6 @@ CPU တည်ဆောက်ပုံ - %2 file empty ဖိုင် လွတ်နေသည် - - malformed string - စံမမှီသော စာကြောင်း - - - missing closing quote - အပိတ်အမှတ်အသား လိုနေသည် - - - %1: (row, col) %2,%3 - %1: (အတန်း၊ ကော်လံ) %2,%3 - AES 256-bit AES 256-bit @@ -8647,13 +9107,89 @@ This option is deprecated, use --set-key-file instead. - Unsupported KDF type, cannot decrypt json file + Unknown passkeys error - Unknown passkeys error + Invalid KDF iterations, cannot decrypt json file + + Unsupported format, ensure your Bitwarden export is password-protected + + + + Only PBKDF and Argon2 are supported, cannot decrypt json file + + + + Reset Shortcuts + + + + Double click an action to change its shortcut + + + + Filter... + + + + Shortcut Conflict + + + + Shortcut %1 conflicts with '%2'. Overwrite shortcut? + + + + Cannot generate valid passphrases because the wordlist is too short + + + + Encrypted files are not supported. + + + + Proton Pass Import + + + + Delete plugin data? + ချိတ်ဆက်ပရိုဂရမ် အချက်အလက်ကို ဖျက်မလား။ + + + Delete plugin data from Entry(s)? + + + + Passkey + + + + Format to use when exporting. Available choices are 'xml', 'csv' or 'html'. Defaults to 'xml'. + + + + start minimized to the system tray + + + + malformed string, possible unescaped delimiter + + + + missing closing delimiter + + + + %1, row: %2, column: %3 + + + + Tags + ပူးတွဲမှုများ + QtIOCompressor @@ -8689,6 +9225,37 @@ This option is deprecated, use --set-key-file instead. စက်တွင်း zlib ပြဿနာ - + + RemoteHandler + + Command `%1` did not finish in time. Process was killed. + + + + Failed to upload merged database. Command `%1` did not finish in time. Process was killed. + + + + Invalid download parameters provided. + + + + Command `%1` failed to download database. + + + + Invalid database pointer or upload parameters provided. + + + + Command `%1` exited with status code: %2 + + + + Failed to upload merged database. Command `%1` exited with status code: %2 + + + ReportsWidgetBrowserStatistics @@ -8755,6 +9322,10 @@ This option is deprecated, use --set-key-file instead. Exclude from reports အစီရင်ခံစာများမှ ဖယ်ရန် + + Expire Entry(s)… + + Only show entries that have a URL @@ -8771,36 +9342,33 @@ This option is deprecated, use --set-key-file instead. (Expired) + + Delete plugin data from Entry(s)… + + ReportsWidgetHealthcheck - Hover over reason to show additional details. Double-click entries to edit. - ထပ်ဆောင်း အသေးစိတ်အချက်အလက်များကို ပြရန် အကြောင်းရင်းပေါ်တွင် ထောက်ပါ။ ဖြည့်သွင်းချက်များကို တည်းဖြတ်ရန် နှစ်ချက်နှိပ်ပါ။ + Show expired entries + - Bad - Password quality - ဆိုးသည် + (Expired) + + + + Hover over reason to show additional details. Double-click entries to edit. + ထပ်ဆောင်း အသေးစိတ်အချက်အလက်များကို ပြရန် အကြောင်းရင်းပေါ်တွင် ထောက်ပါ။ ဖြည့်သွင်းချက်များကို တည်းဖြတ်ရန် နှစ်ချက်နှိပ်ပါ။ Bad — password must be changed ဆိုးသည် — စကားဝှက် ပြောင်းရမည် - - Poor - Password quality - ညံ့ - Poor — password should be changed ညံ့သည် — စကားဝှက် ပြောင်းသင့်သည် - - Weak - Password quality - အားနည်း - Weak — consider changing the password အားနည်းသည် — စကားဝှက်ပြောင်းရန် စဉ်းစားပါ @@ -8849,18 +9417,14 @@ This option is deprecated, use --set-key-file instead. Exclude from reports အစီရင်ခံစာများမှ ဖယ်ရန် - - Show expired entries - + + Expire Entry(s)… + Show entries that have been excluded from reports - - (Expired) - - ReportsWidgetHibp @@ -8956,6 +9520,10 @@ This option is deprecated, use --set-key-file instead. Exclude from reports အစီရင်ခံစာများမှ ဖယ်ရန် + + Expire Entry(s)… + + ReportsWidgetPasskeys @@ -9197,6 +9765,14 @@ This option is deprecated, use --set-key-file instead. No agent running, cannot list identities. လည်ပတ်နေသော အေးဂျင့် မရှိပါ၊ ကိုယ်ပိုင်အမှတ်သင်္ကေတများကို မဖော်ပြနိုင်ပါ။ + + Failed to remove all SSH identities from agent. + + + + All SSH identities removed from agent. + + SearchHelpWidget @@ -9482,29 +10058,6 @@ This option is deprecated, use --set-key-file instead. %1 သို့ တင်ပို့ပါ - - ShortcutSettingsWidget - - Double click an action to change its shortcut - - - - Shortcut Conflict - - - - Filter... - - - - Shortcut %1 conflicts with '%2'. Overwrite shortcut? - - - - Reset Shortcuts - - - TagModel @@ -9794,11 +10347,15 @@ Example: JBSWY3DPEHPK3PXP ဟာ့ဝဲ စကားဝှက်သော့များ ရှာမတွေ့ပါ - <p>If you own a <a href="https://www.yubico.com/">YubiKey</a> or <a href="https://onlykey.io">OnlyKey</a>, you can use it for additional security.</p><p>The key requires one of its slots to be programmed as <a href="https://docs.yubico.com/yesdk/users-manual/application-otp/challenge-response.html">HMAC-SHA1 Challenge-Response</a>.</p> + Refresh hardware keys - Refresh hardware keys + <p>If you own a <a href="https://www.yubico.com/">YubiKey</a> or <a href="https://onlykey.io">OnlyKey</a>, you can use it for additional security.</p><p>The key requires one of its slots to be programmed with <a href="https://keepassxc.org/docs/#faq-yubikey-howto">Challenge-Response</a>.</p> + + + + Hardware keys found, but no slots are configured diff --git a/share/translations/keepassxc_nb.ts b/share/translations/keepassxc_nb.ts index 8389e5eee..ab893851f 100644 --- a/share/translations/keepassxc_nb.ts +++ b/share/translations/keepassxc_nb.ts @@ -217,18 +217,50 @@ You must restart the application to set the new language. Would you like to restart now? Du må starte programmet på nytt for å angi det nye språket. Vil du starte på nytt nå? - - Reset Settings? - Tilbakestill innstillinger? - - - Are you sure you want to reset all general and security settings to default? - Er du sikker på at du vil tilbakestille alle generelle og sikkerhetsinnstillinger til standard? - Select backup storage directory Velg lagringsmappe for sikkerhetskopiering + + Confirm Reset + + + + Are you sure you want to reset all settings to default? + + + + Import KeePassXC Settings + + + + Failed to import settings from %1, not a valid settings file. + + + + Export KeePassXC Settings + + + + Small + + + + Normal + + + + Medium + + + + Large + + + + Custom + + ApplicationSettingsWidgetGeneral @@ -280,25 +312,6 @@ Include beta releases when checking for updates Ta med betaversjoner når du ser etter oppdateringer - - On database unlock, show entries that - Ved databaseopplåsing, vis oppføringer som - - - have expired - On database unlock, show entries that... - er utløpt - - - days - On database unlock, show entries that will expire within %1 days - dager - - - will expire within - On database unlock, show entries that... - vil utløpe innen - File Management Filhåndtering @@ -323,22 +336,10 @@ Backup database file before saving Sikkerhetskopier database-filen før lagring - - Backup destination - Mål for sikkerhetskopiering - - - Specifies the database backup file location. Occurrences of "{DB_FILENAME}" are replaced with the filename of the saved database without extension. {TIME:<format>} is replaced with the backup time, see https://doc.qt.io/qt-5/qdatetime.html#toString. <format> defaults to format string "dd_MM_yyyy_hh-mm-ss". - Angir filplasseringen til database-sikkerhetskopien. Forekomster av {DB_FILENAME} erstattes med filnavnet til den lagrede databasen uten filtype. {TIME:<format>} erstattes med sikkerhetskopi-tidspunktet, se https://doc.qt.io/qt-5/qdatetime.html#toString. <format>standardformatet er "dd_MM_yyyy_hh-mm-ss". - {DB_FILENAME}.old.kdbx {DB_FILENAME}.old.kdbx - - Choose... - Velg… - Use alternative saving method (may solve problems with Dropbox, Google Drive, GVFS, etc.) Bruk alternativ lagringsmetode (kan løse problemer med Dropbox, Google Drive, GVFS, etc.) @@ -505,6 +506,71 @@ Remember last typed entry for: Husk siste inntasta oppføring i: + + On database unlock, show entries that will expire within + + + + On database unlock, show entries that will expire within + + + + days + number of days warning for password expiration + dager + + + Destination format: + + + + <html><head/><body><p><span style=" font-weight:600;">{DB_FILENAME}</span> is replaced with the filename of the saved database without extension</p><p><span style=" font-weight:600;">{TIME:&lt;format&gt;}</span> is replaced with the specified time format (default: dd_MM_yyyy_hh-mm-ss)</p><p>See the User Guide for more details</p></body></html> + + + + Choose folder... + + + + Show confirmation before moving entries to recycle bin + + + + Copy data on double clicking field in entry view + + + + Show toolbar + + + + Show the menu bar by pressing the Alt key + + + + Show menubar + + + + Import settings… + + + + Export settings… + + + + Open browser on double clicking URL field in entry view + + + + Font size: + + + + Font size selection + + ApplicationSettingsWidgetSecurity @@ -570,18 +636,6 @@ Hide passwords in the entry preview panel Skjul passord i oppføringspanelet - - Hide entry notes by default - Skjul notater i oppføringa som standard - - - Move entries to recycle bin without confirmation - Flytt oppføringer til søppelbøtte uten bekreftelse - - - Enable double click to copy the username/password entry columns - Aktiver dobbeltklikk for å kopiere brukernavn-/passord-oppføringer - Privacy Personvern @@ -594,6 +648,18 @@ Hide TOTP in the entry preview panel Skjul TOTP i forhåndsvisningspanelet + + Lock databases when switching user + + + + Lock Options + + + + Hide notes in the entry preview panel + + AutoType @@ -641,20 +707,6 @@ Entry does not have attribute for PICKCHARS: %1 Oppføringen har ikke attributt for PICKCHARS: %1 - - Invalid conversion type: %1 - Ugyldig konverteringstype: %1 - - - Invalid conversion syntax: %1 - Ugyldig konverteringssyntaks: %1 - - - Invalid regular expression syntax %1 -%2 - Ugyldig syntaks for regulært uttrykk %1 -%2 - Invalid placeholder: %1 Ugyldig posisjonsmerke: %1 @@ -714,7 +766,7 @@ Trying to send invalid keyboard symbol. - + Forsøker å sende et ugyldig tastatursymbol. @@ -886,24 +938,25 @@ Vennligst velge riktig database for å lagre identifikasjon. Add to existing entry - + Legg til i eksisterende oppføring Existing passkey found. Do you want to register a new passkey for: - + Eksisterende tilgangsnøkkel funnet. +Vil du registrere en ny tilgangsnøkkel for: Select the existing passkey and press Update to replace it. - + Velg den eksisterende tilgangsnøkkelen, og trykk oppdater for å erstatte den. Authenticate passkey credentials for: - + Godkjenn tilgangsnøkkellegitimasjon for: Do you want to register a passkey for: - + Vil du registrere tilgangsnøkkel for: @@ -986,16 +1039,17 @@ Vil du slette oppføringen? Register a new passkey to this entry: - + Registrer ny tilgangsnøkkel på denne oppføringen: KeePassXC - Update passkey - + KeePassXC - Oppdater tilgangsnøkkel Entry already has a passkey. Do you want to overwrite the passkey in %1 - %2? - + Oppføringen har allerede en tilgangsnøkkel. +Vil du erstatte tilgangsnøkkelen i %1 - %2? Register @@ -1020,10 +1074,6 @@ Do you want to overwrite the passkey in %1 - %2? General Generelt - - Browsers installed as snaps are currently not supported. - Nettlesere installert som Snap støttes ikke for øyeblikket. - Enable integration for these browsers: Bruk tillegget i disse nettleserne: @@ -1195,18 +1245,6 @@ Do you want to overwrite the passkey in %1 - %2? Custom extension ID Egendefinert utvidelse-ID - - Due to Snap sandboxing, you must run a script to enable browser integration.<br />You can obtain this script from %1 - På grunn av Snap-sandkasse må du kjøre et skript for å aktivere nettleserintegrasjon.<br />Du kan få tak i dette skriptet fra %1 - - - KeePassXC-Browser is needed for the browser integration to work. <br />Download it for %1 and %2 and %3. %4 - KeePassXC-Browser er nødvendig for at nettleserintegrasjonen skal fungere. <br />Last den ned for %1 og %2 og %3. %4 - - - Please see special instructions for browser extension use below - Vennligst se spesielle instruksjoner for bruk av nettleserutvidelse nedenfor - Executable Files Kjørbare filer @@ -1249,10 +1287,18 @@ Do you want to overwrite the passkey in %1 - %2? Allows using insecure http://localhost with passkeys for testing purposes. - + Tillater bruk av usikre http://localhost med tilgangsnøkler for testformål. Allow using localhost with passkeys + Tillat bruk av localhost med tilgangsnøkler + + + KeePassXC-Browser is needed for the browser integration to work. <br />Download it for %1 and %2 and %3. + + + + Browsers installed using Snap or Flatpak are not supported with exception to Firefox installed using Snap. @@ -1391,12 +1437,25 @@ Do you want to overwrite the passkey in %1 - %2? Failed to parse CSV file: %1 - + Kunne ikke tolke CSV-fil: %1 Imported from CSV file: %1 + Importert fra CSV-fil: %1 + + + No Title Selected + + No title column was selected, entries will be hard to tell apart. +Are you sure you want to import? + + + + Tags + Tagger + CsvParserModel @@ -1460,6 +1519,14 @@ Sikkerhetskopi av database lokalisert på %2 Recycle Bin Papirkurv + + Database file read error. + + + + No file path was provided. + + DatabaseOpenDialog @@ -1602,50 +1669,58 @@ For å forhindre at denne feilen vises, må du gå til "Databaseinnstilling Select Key File: - + Velg nøkkelfil: <p>In addition to a password, you can use a secret file to enhance the security of your database. This file can be generated in your database's security settings.</p><p>This is <strong>not</strong> your *.kdbx database file!</p> - - - - Click to add a key file. - - - - <a href="#" style="text-decoration: underline">I have a key file</a> - + <p>I tillegg til passord, kan du bruke en nøkkelfil for å forbedre sikkerheten til databasen. Denne fila kan opprettes i databasens sikkerhetsinnstillinger.</p> <p>Dette er <strong>ikke</strong> *.kdbx-databasefilen din!</p> Use hardware key [Serial: %1] - + Bruk maskinvarenøkkel [Serial: %1] Use hardware key - + Bruk maskinvarenøkkel Your database file is NOT a key file! If you don't have a key file or don't know what that is, you don't have to select one. - + Database-filen er IKKE en nøkkelfil! +Om du ikke har en nøkkelfil, eller ikke vet hva det er, trenger du ikke velge en. KeePassXC database file selected - + KeePassXC-databasefil valgt The file you selected looks like a database file. A database file is NOT a key file! Are you sure you want to continue with this file?. - + Filen du har valgt ser ut som en databasefil. +En databasefil er IKKE en nøkkelfil! + +Er du sikker på at du vil fortsette med denne filen? No hardware keys found. - + Finner ingen maskinvarenøkler. Refresh Hardware Keys + Oppdater maskinvarenøkler + + + Click to add a key file. + Trykk for å legge til en nøkkelfil + + + <a href="#" style="text-decoration: underline">I have a key file</a> + <a href="#" style="text-decoration: underline">Jeg har en nøkkelfil</a> + + + Hardware keys found, but no slots are configured. @@ -1682,6 +1757,22 @@ Are you sure you want to continue with this file?. Maintenance Vedlikehold + + KeeShare + KeeShare + + + Secret Service Integration + Integrasjon av 'Secret Service' + + + Remote Sync + Fjernsynkronisering + + + Database Settings: %1 + + DatabaseSettingsWidgetBrowser @@ -1852,14 +1943,14 @@ Er du sikker på at du vil fortsette uten passord? Weak password Svakt passord - - You must enter a stronger password to protect your database. - Du må legge inn et sterkere passord for å beskytte databasen din. - This is a weak password! For better protection of your secrets, you should choose a stronger password. Dette er et svakt passord! For bedre beskyttelse av hemmelighetene dine, bør du velge et sterkere passord. + + The provided password does not meet the minimum quality requirement. + + DatabaseSettingsWidgetEncryption @@ -2161,6 +2252,50 @@ fjernet fra databasen. Autosave delay since last change checkbox Autolagringsforsinkelse siden siste endring i avkrysningsboksa + + Public Database Metadata + + + + Warning: the following settings are not encrypted. + + + + Display name: + + + + Publically visible display name used on the unlock dialog + + + + Database public display name + + + + Display color: + + + + Publically visible color used on the unlock dialog + + + + Database public display color chooser + + + + Clear + Tøm + + + Display icon: + + + + Select Database Icon + + DatabaseSettingsWidgetKeeShare @@ -2256,6 +2391,129 @@ fjernet fra databasen. Database-beskrivelsesfelt + + DatabaseSettingsWidgetRemote + + Sync Commands + + + + Remove + Fjern + + + Command Settings + + + + Name + Navn + + + Save + Lagre + + + Download + Last ned + + + Command: + + + + Download command field + + + + e.g.: "sftp user@hostname" or "scp user@hostname:DatabaseOnRemote.kdbx {TEMP_DATABASE}" + + + + Input: + + + + Download input field + + + + Upload + Last opp + + + Upload command field + + + + e.g.: "sftp user@hostname" or "scp {TEMP_DATABASE} user@hostname:DatabaseOnRemote.kdbx" + + + + Upload input field + + + + Name cannot be empty. + Navn kan ikke være tomt. + + + Test + Test + + + Download command cannot be empty. + + + + Download failed with error: %1 + + + + Download finished, but file %1 could not be found. + + + + Download successful. + Nedlasting fullført. + + + Save Remote Settings + + + + You have unsaved changes. Do you want to save them? + Du har endringer som ikke er lagret. Vil du lagre dem? + + + e.g.: +get DatabaseOnRemote.kdbx {TEMP_DATABASE} +exit +--- +{TEMP_DATABASE} is used as placeholder to store the database in a temporary location +The command has to exit. In case of `sftp` as last command `exit` has to be sent + + + + + e.g.: +put {TEMP_DATABASE} DatabaseOnRemote.kdbx +exit +--- +{TEMP_DATABASE} is used as placeholder to store the database in a temporary location +The command has to exit. In case of `sftp` as last command `exit` has to be sent + + + + + Timeout: + + + + seconds + sekunder + + DatabaseTabWidget @@ -2329,6 +2587,11 @@ Dette er definitivt en feil, rapporter det til utviklerne. Database tab name modifier %1 [Låst] + + %1 [Temporary] + Database tab name modifier + + DatabaseWidget @@ -2452,26 +2715,6 @@ Lagre endringer? File has changed Fil er endret - - The database file has changed. Do you want to load the changes? - Databasen er endret. Ønsker du å laste inn endringene? - - - Merge Request - Forespørsel om sammenslåing - - - The database file has changed and you have unsaved changes. -Do you want to merge your changes? - Databasefila er endra og du har ulagra endringer. -Vil du slå sammen fila med endringene dine? - - - Could not open the new database file while attempting to autoreload. -Error: %1 - Kunne ikke åpne den nye databasefilen under forsøk på å laste den inn på nytt automatisk. -Feil: %1 - Disable safe saves? Deaktivere sikker lagring? @@ -2523,6 +2766,86 @@ Deaktivere sikker lagring og prøve igjen? Database tab name modifier %1 [Ny Database] + + Remote Sync did not contain any download or upload commands. + + + + Remote sync '%1' completed successfully! + + + + Remote sync '%1' failed: %2 + + + + Error while saving database %1: %2 + + + + Downloading... + Laster ned... + + + Uploading... + Laster opp... + + + Syncing... + Synkroniserer... + + + Remove passkey from entry + Fjern tilgangsnøkkel fra oppføringen + + + Do you want to remove the passkey from this entry? + Vil du fjerne tilgangsnøkkelen fra denne oppføringen? + + + The database file "%1" was modified externally + + + + Do you want to load the changes? + + + + Reload database + + + + Reloading database… + + + + Reload canceled + + + + Reload successful + + + + Reload pending user action… + + + + The database file "%1" was modified externally.<br>How would you like to proceed?<br><br>Merge all changes<br>Ignore the changes on disk until save<br>Discard unsaved changes + + + + The database file "%1" was modified externally.<br>How would you like to proceed?<br><br>Merge all changes then save<br>Overwrite the changes on disk<br>Discard unsaved changes + + + + Database file overwritten. + + + + Database file on disk cannot be unlocked with current credentials.<br>Enter new credentials and/or present hardware key to continue. + + EditEntryWidget @@ -2574,10 +2897,6 @@ Deaktivere sikker lagring og prøve igjen? n/a i/a - - (encrypted) - (kryptert) - Select private key Velg privat nøkkel @@ -2680,6 +2999,10 @@ Vil du rette den? %n year(s) %n år%n år + + Failed to decrypt SSH key, ensure password is correct. + Kunne ikke dekryptere SSH-nøkkelen. Sørg for at passordet er korrekt. + EditEntryWidgetAdvanced @@ -2851,18 +3174,10 @@ Vil du rette den? Skip Auto-Submit for this entry Hopp over automatisk utførelse for denne oppføringen - - Only send this setting to the browser for HTTP Auth dialogs. If enabled, normal login forms will not show this entry for selection. - Send denne innstillingen bare til nettleseren for «HTTP Auth»-dialoger. Hvis aktivert vil ikke vanlige påloggingsskjemaer få vist denne oppføringen for valg. - Use this entry only with HTTP Basic Auth Bruk denne oppføringen bare med «HTTP Basic Auth» - - Do not send this setting to the browser for HTTP Auth dialogs. If enabled, HTTP Auth dialogs will not show this entry for selection. - Ikke send denne innstillingen til nettleseren for «HTTP Auth»-dialoger. Hvis aktivert viser ikke «HTTP Auth»-dialoger denne oppføringen for valg. - Do not use this entry with HTTP Basic Auth Ikke bruk denne oppføringen med «HTTP Basic Auth» @@ -2881,10 +3196,18 @@ Vil du rette den? These settings affect the entry's behaviour with the browser extension. - + Disse innstillingene påvirker oppføringens atferd med nettleserutvidelsen. Additional URLs + Ytterligere URL-er + + + Only send this entry to the browser for HTTP Auth dialogs. If enabled, normal login forms will not show this entry for selection. + + + + Do not send this entry to the browser for HTTP Auth dialogs. If enabled, HTTP Auth dialogs will not show this entry for selection. @@ -3109,6 +3432,10 @@ Vil du rette den? seconds sekunder + + Clear agent + + EditGroupWidget @@ -3551,6 +3878,24 @@ Dette kan føre til feil for de berørte programtilleggene. %1 - Clone %1 - Klone + + Passkey + Tilgangsnøkkel + + + Invalid conversion type: %1 + Ugyldig konverteringstype: %1 + + + Invalid conversion syntax: %1 + Ugyldig konverteringssyntaks: %1 + + + Invalid regular expression syntax %1 +%2 + Ugyldig syntaks for regulært uttrykk %1 +%2 + EntryAttachments @@ -3559,6 +3904,21 @@ Dette kan føre til feil for de berørte programtilleggene. Kan ikke åpne filen %1 + + EntryAttachmentsDialog + + Form + Skjema + + + File name + + + + File contents... + + + EntryAttachmentsModel @@ -3596,14 +3956,6 @@ Dette kan føre til feil for de berørte programtilleggene. Remove Fjern - - Rename selected attachment - Gi nytt navn til valgt vedlegg - - - Rename - Gi nytt navn - Open selected attachment Åpne valgt vedlegg @@ -3719,6 +4071,18 @@ Would you like to overwrite the existing attachment? Vedlegg %1 finnes allerede. Vil du erstatte det eksisterende vedlegget? + + New + + + + Preview + Forhåndsvis + + + Failed to preview an attachment: Attachment not found + + EntryAttributesModel @@ -3917,6 +4281,10 @@ Vil du erstatte det eksisterende vedlegget? Background Color Bakgrunnsfarge + + Group Path + + EntryPreviewWidget @@ -4279,7 +4647,7 @@ Du kan aktivere DuckDuckGo-ikonetjenesten i sikkerhetsdelen av applikasjonsinnst ImportWizard Import Wizard - + Importeringsveileder @@ -4290,7 +4658,7 @@ Du kan aktivere DuckDuckGo-ikonetjenesten i sikkerhetsdelen av applikasjonsinnst Entry count: %1 - + Antall oppføringer: %1 Group @@ -4310,6 +4678,14 @@ Du kan aktivere DuckDuckGo-ikonetjenesten i sikkerhetsdelen av applikasjonsinnst Url + URL + + + Could not load key file. + + + + Could not open remote database. Password or key file may be incorrect. @@ -4321,7 +4697,7 @@ Du kan aktivere DuckDuckGo-ikonetjenesten i sikkerhetsdelen av applikasjonsinnst Import File Selection - + Importer filutvalg Password: @@ -4337,7 +4713,7 @@ Du kan aktivere DuckDuckGo-ikonetjenesten i sikkerhetsdelen av applikasjonsinnst Import Into: - + Importer til: New Database @@ -4345,35 +4721,35 @@ Du kan aktivere DuckDuckGo-ikonetjenesten i sikkerhetsdelen av applikasjonsinnst No unlocked databases available - + Ingen åpne databaser tilgjengelig Existing Database: - + Eksisterende database: Import File: - + Importer fil: Comma Separated Values (.csv) - + Kommaseparerte verdier (.csv) 1Password Export (.1pux) - + Eksporter for 1Password (.1pux) 1Password Vault (.opvault) - + 1Password-hvelv (.opvault) Bitwarden (.json) - + Bitwarden (.json) KeePass 1 Database (.kdb) - + KeePass 1-database (.kdb) Open OPVault @@ -4381,7 +4757,7 @@ Du kan aktivere DuckDuckGo-ikonetjenesten i sikkerhetsdelen av applikasjonsinnst Select import file - + Velg fil å importere All files @@ -4397,22 +4773,60 @@ Du kan aktivere DuckDuckGo-ikonetjenesten i sikkerhetsdelen av applikasjonsinnst Comma Separated Values - + Kommaseparerte verdier 1Password Export - + Eksporter for 1Password Bitwarden JSON Export - + Eksporter som Bitwarden JSON 1Password Vault - + 1Password-hvelv KeePass1 Database + KeePass1-database + + + Proton Pass (.json) + + + + Proton Pass JSON Export + + + + Temporary Database + + + + Command: + + + + e.g.: "sftp user@hostname" or "scp user@hostname:DatabaseOnRemote.kdbx {TEMP_DATABASE}" + + + + Input: + + + + e.g.: +get DatabaseOnRemote.kdbx {TEMP_DATABASE} +exit +--- +{TEMP_DATABASE} is used as placeholder to store the database in a temporary location +The command has to exit. In case of `sftp` as last commend `exit` has to be sent + + + + + Remote Database (.kdbx) @@ -5500,7 +5914,7 @@ Er du sikker på at du vil fortsette med denne filen? Show Menubar - + Vis menylinje Show Toolbar @@ -5555,12 +5969,6 @@ Denne versjonen er ikke ment for produksjonsmiljø. Expect some bugs and minor issues, this version is meant for testing purposes. MERK: Du bruker en forhåndsversjon av KeePassXC. Forvent enkelte feil og mindre problemer, denne versjonen er ment for testformål. - - - WARNING: Your Qt version may cause KeePassXC to crash with an On-Screen Keyboard. -We recommend you use the AppImage available on our downloads page. - ADVARSEL: Qt-versjonen din kan føre til at KeePassXC krasjer med et skjermtastatur. -Vi anbefaler at du bruker det AppImage som er tilgjengelig på nedlastingssidene våre. No Tags @@ -5616,15 +6024,15 @@ Vi anbefaler at du bruker det AppImage som er tilgjengelig på nedlastingssidene 1Password 1PUX... - + 1Password 1PUX Import a 1Password 1PUX file - + Importer en 1Password 1PUX-fil Import… - + Importer… Passkeys… @@ -5634,6 +6042,10 @@ Vi anbefaler at du bruker det AppImage som er tilgjengelig på nedlastingssidene Import Passkey Importer tilgangsnøkkel + + Remote S&ync… + Fjernsynkronisering... + Quit Application Avslutt programmet @@ -5738,6 +6150,10 @@ Vi anbefaler at du bruker det AppImage som er tilgjengelig på nedlastingssidene Show Password Generator Vis passordgenerator + + Remove Passkey From Entry + Slett tilgangsnøkkel fra oppføring + Perform Auto-Type: {USERNAME} Utfør autoskriv: {BRUKERNAVN} @@ -5852,7 +6268,7 @@ Vi anbefaler at du bruker det AppImage som er tilgjengelig på nedlastingssidene Toggle Show Menubar - + Vis/skjul menylinje Toggle Show Toolbar @@ -5882,6 +6298,34 @@ Vi anbefaler at du bruker det AppImage som er tilgjengelig på nedlastingssidene Toggle Allow Screen Capture Veksle tillat skjermopptak av/på + + Show Group Panel + + + + Toggle Show Group Panel + + + + Setup Remote Sync… + + + + Password Generator + Passordgenerator + + + E&xpire Entry… + + + + Clear SSH Agent + + + + Clear all identities in ssh-agent + + ManageDatabase @@ -6032,6 +6476,25 @@ Vi anbefaler at du bruker det AppImage som er tilgjengelig på nedlastingssidene Fyll ut visningsnavnet og en valgfri beskrivelse av den nye databasen: + + NewEntryAttachmentsDialog + + Attachment name cannot be empty + + + + Attachment with the same name already exists + + + + Save attachment + + + + New entry attachment + + + NixUtils @@ -6219,6 +6682,10 @@ Vi anbefaler at du bruker det AppImage som er tilgjengelig på nedlastingssidene Unexpected EOF when writing private key Uventet EOF ved skriving av privat nøkkel + + (encrypted) + (kryptert) + OpenSSHKeyGenDialog @@ -6267,7 +6734,7 @@ Vi anbefaler at du bruker det AppImage som er tilgjengelig på nedlastingssidene Export the following passkey entries. - + Eksporter følgende tilgangsnøkkeloppføringer. @@ -6340,15 +6807,15 @@ Vil du erstatte den? Import the following passkey: - + Importer følgende tilgangsnøkkel: Import the following passkey to this entry: - + Importer følgende tilgangsnøkkel til denne oppføringen: Default passkeys group (Imported Passkeys) - + Standardgruppe for tilgangsnøkler (importerte tilgangsnøkler) @@ -6371,15 +6838,15 @@ Vil du erstatte den? Open passkey file - + Åpne tilgangsnøkkelfil Cannot import passkey - + Kunne ikke importere tilgangsnøkkel Cannot import passkey file "%1". Data is missing. - + Kan ikke importere tilgangsnøkkelfil "%1". Data mangler. Cannot import passkey file "%1". @@ -6570,10 +7037,6 @@ The following data is missing: Also choose from: Velg også mellom: - - Excluded characters: "0", "1", "l", "I", "O", "|", "﹒" - Ekskluderte tegn: "0", "1", "l", "I", "O", "|", "﹒" - Exclude look-alike characters Ekskluder tegn som er nesten makne @@ -6598,10 +7061,6 @@ The following data is missing: Word Count: Antall ord: - - Character Count: - Antall tegn: - Word Case: Ord-format: @@ -6614,10 +7073,6 @@ The following data is missing: Add custom wordlist Legg til egendefinert ordliste - - character - tegn - Close Lukk @@ -6724,6 +7179,22 @@ Vil du erstatte den? Special Characters Spesialtegn + + passwordLength + + + + Characters: %1 + + + + MIXED case + + + + Excluded characters: "0", "1", "l", "I", "O", "|", "﹒", "B", "8", "G", "6" + + PasswordWidget @@ -6791,6 +7262,21 @@ Vil du erstatte den? Trykk &Tab mellom tegn + + PreviewEntryAttachmentsDialog + + Preview entry attachment + + + + No preview available + + + + Image format not supported + + + QMessageBox @@ -7469,10 +7955,6 @@ Vil du erstatte den? Invalid word count %1 Ugyldig ordtelling %1 - - The word list is too small (< 1000 items) - Ordlisten er for liten (< 1000 element) - Title for the entry. Tittel for oppføringa. @@ -7617,10 +8099,6 @@ Vil du erstatte den? Exit interactive mode. Avslutt interaktiv modus. - - Format to use when exporting. Available choices are 'xml' or 'csv'. Defaults to 'xml'. - Format som skal brukes ved eksport. Tilgjengelige valg er XML eller CSV. Standardvalg er XML. - Exports the content of a database to standard output in the specified format. Eksporterer innholdet av en database til standard output i det angitte formatet. @@ -8209,18 +8687,6 @@ Kjerne: %3 %4 file empty fil tom - - malformed string - Deformert streng - - - missing closing quote - Manglende avsluttende anførselstegn - - - %1: (row, col) %2,%3 - %1: (rad, kolonne) %2,%3 - AES 256-bit AES 256-biter @@ -8468,7 +8934,7 @@ This option is deprecated, use --set-key-file instead. Databases have been locked. - + Databasen har blitt låst. Attestation not supported @@ -8585,15 +9051,15 @@ This option is deprecated, use --set-key-file instead. Favorite Tag for favorite entries - + Favoritt File does not exist. - + Filen eksisterer ikke. Cannot open file: %1 - + Kunne ikke åpne fil: %1 Cannot parse file: %1 at position %2 @@ -8613,7 +9079,7 @@ This option is deprecated, use --set-key-file instead. Wrong password - + Feil passord Invalid encrypted data field @@ -8629,16 +9095,16 @@ This option is deprecated, use --set-key-file instead. Cannot decrypt data - + Kan ikke dekryptere data Bitwarden Import - + Importer fra Bitwarden Archived Tag for archived entries - + Arkivert Invalid 1PUX file format: Not a valid ZIP file. @@ -8650,28 +9116,104 @@ This option is deprecated, use --set-key-file instead. 1Password Import - + Importer fra 1Password Enter Shortcut - + Skriv in snarvei Action - + Handling Shortcuts - - - - Unsupported KDF type, cannot decrypt json file - + Snarveier Unknown passkeys error + + Invalid KDF iterations, cannot decrypt json file + + + + Unsupported format, ensure your Bitwarden export is password-protected + + + + Only PBKDF and Argon2 are supported, cannot decrypt json file + + + + Reset Shortcuts + Tilbakestill snarveier + + + Double click an action to change its shortcut + Dobbeltrykk på en handling for å endre snarveien + + + Filter... + Filtrer... + + + Shortcut Conflict + Snarveikonflikt + + + Shortcut %1 conflicts with '%2'. Overwrite shortcut? + + + + Cannot generate valid passphrases because the wordlist is too short + + + + Encrypted files are not supported. + + + + Proton Pass Import + + + + Delete plugin data? + Slett programtillegg-data? + + + Delete plugin data from Entry(s)? + + + + Passkey + Tilgangsnøkkel + + + Format to use when exporting. Available choices are 'xml', 'csv' or 'html'. Defaults to 'xml'. + + + + start minimized to the system tray + + + + malformed string, possible unescaped delimiter + + + + missing closing delimiter + + + + %1, row: %2, column: %3 + + + + Tags + Tagger + QtIOCompressor @@ -8707,6 +9249,37 @@ This option is deprecated, use --set-key-file instead. Intern zlib-feil: + + RemoteHandler + + Command `%1` did not finish in time. Process was killed. + + + + Failed to upload merged database. Command `%1` did not finish in time. Process was killed. + + + + Invalid download parameters provided. + + + + Command `%1` failed to download database. + + + + Invalid database pointer or upload parameters provided. + + + + Command `%1` exited with status code: %2 + + + + Failed to upload merged database. Command `%1` exited with status code: %2 + + + ReportsWidgetBrowserStatistics @@ -8773,6 +9346,10 @@ This option is deprecated, use --set-key-file instead. Exclude from reports Utelat fra rapporter + + Expire Entry(s)… + + Only show entries that have a URL Vis bare oppføringer som har en URL @@ -8789,36 +9366,33 @@ This option is deprecated, use --set-key-file instead. (Expired) (Utløpt) + + Delete plugin data from Entry(s)… + + ReportsWidgetHealthcheck - Hover over reason to show additional details. Double-click entries to edit. - Hold pekeren over årsaken for å vise flere detaljer. Dobbeltklikk på oppføringer for å redigere. + Show expired entries + Vis utløpte oppføringer - Bad - Password quality - Dårlig + (Expired) + (Utløpt) + + + Hover over reason to show additional details. Double-click entries to edit. + Hold pekeren over årsaken for å vise flere detaljer. Dobbeltklikk på oppføringer for å redigere. Bad — password must be changed Dårlig – passordet må endres - - Poor - Password quality - Dårlig - Poor — password should be changed Dårlig – passordet bør endres - - Weak - Password quality - Svak - Weak — consider changing the password Svakt – vurder å endre passordet @@ -8867,18 +9441,14 @@ This option is deprecated, use --set-key-file instead. Exclude from reports Ekskluder fra rapporter - - Show expired entries - Vis utløpte oppføringer + + Expire Entry(s)… + Show entries that have been excluded from reports Vis oppføringer som er ekskluderte fra rapporter - - (Expired) - (Utløpt) - ReportsWidgetHibp @@ -8974,6 +9544,10 @@ This option is deprecated, use --set-key-file instead. Exclude from reports Ekskluder fra rapporter + + Expire Entry(s)… + + ReportsWidgetPasskeys @@ -9039,7 +9613,7 @@ This option is deprecated, use --set-key-file instead. No entries with passkeys. - + Ingen oppføringer med tilgangsnøkler. @@ -9215,6 +9789,14 @@ This option is deprecated, use --set-key-file instead. No agent running, cannot list identities. Ingen agent kjører, kan ikke liste opp identiteter. + + Failed to remove all SSH identities from agent. + + + + All SSH identities removed from agent. + + SearchHelpWidget @@ -9393,7 +9975,7 @@ This option is deprecated, use --set-key-file instead. <html><head/><body><p>This improves compatibility with certain applications which search for password without unlocking the database first.</p><p>But enabling this may also crash the client if the database can not be unlocked within a certain timeout. (Usually 25s, but may be a different value set in applications.) </p></body></html> - + <html><head/><body><p>Dette forbedrer kompatibiliteten med enkelte programmer som søker etter passord uten å først låse opp databasen.</p><p>Men å aktivere dette kan også føre til at klienten krasjer, hvis databasen ikke kan låses opp i løpet av et gitt tidsrom. (Vanligvis 25 sekunder, men kan være en annen verdi angitt i programmene).</p></body></html> @@ -9500,29 +10082,6 @@ This option is deprecated, use --set-key-file instead. Eksporter til %1 - - ShortcutSettingsWidget - - Double click an action to change its shortcut - - - - Shortcut Conflict - - - - Filter... - - - - Shortcut %1 conflicts with '%2'. Overwrite shortcut? - - - - Reset Shortcuts - - - TagModel @@ -9740,7 +10299,7 @@ Eksempel: JBSWY3DPEHPK3PXP Import File - + Importer fil @@ -9812,11 +10371,15 @@ Eksempel: JBSWY3DPEHPK3PXP Ingen maskinvarenøkler oppdaget - <p>If you own a <a href="https://www.yubico.com/">YubiKey</a> or <a href="https://onlykey.io">OnlyKey</a>, you can use it for additional security.</p><p>The key requires one of its slots to be programmed as <a href="https://docs.yubico.com/yesdk/users-manual/application-otp/challenge-response.html">HMAC-SHA1 Challenge-Response</a>.</p> - <p>Hvis du eier en <a href="https://www.yubico.com/">YubiKey</a> eller <a href="https://onlykey.io">OnlyKey</a>, kan du bruke den for ekstra sikkerhet.</p><p>Nøkkelen krever at et av sporene er programmert som <a href="https://docs.yubico.com/yesdk/users-manual/application-otp/utfordrerrespons.html">HMAC-SHA1 utfordrerrespons</a>.</p> + Refresh hardware keys + Oppdater maskinvarenøkler - Refresh hardware keys + <p>If you own a <a href="https://www.yubico.com/">YubiKey</a> or <a href="https://onlykey.io">OnlyKey</a>, you can use it for additional security.</p><p>The key requires one of its slots to be programmed with <a href="https://keepassxc.org/docs/#faq-yubikey-howto">Challenge-Response</a>.</p> + + + + Hardware keys found, but no slots are configured diff --git a/share/translations/keepassxc_nl.ts b/share/translations/keepassxc_nl.ts index ac1290d0c..83f50fe74 100644 --- a/share/translations/keepassxc_nl.ts +++ b/share/translations/keepassxc_nl.ts @@ -215,19 +215,51 @@ You must restart the application to set the new language. Would you like to restart now? - Om de nieuwe taal in te stellen, dient KeePassXC te worden herstart. Wil je dat nu doen? - - - Reset Settings? - Instellingen herstellen? - - - Are you sure you want to reset all general and security settings to default? - Weet je zeker dat je de algemene en beveiligingsinstellingen opnieuw wilt instellen? + Je moet de KeePassXC opnieuw opstarten om de nieuwe taal in te stellen. Wil je dat nu doen? Select backup storage directory - Kies een map voor reservekopie + Selecteer een map voor reservekopie + + + Confirm Reset + Opnieuw instellen bevestigen + + + Are you sure you want to reset all settings to default? + Weet je zeker dat je alle instellingen naar standaard wilt herstellen? + + + Import KeePassXC Settings + KeePassXC-instellingen importeren + + + Failed to import settings from %1, not a valid settings file. + Kan instellingen niet importeren uit %1, geen geldig instellingenbestand. + + + Export KeePassXC Settings + KeePassXC-instellingen exporteren + + + Small + Klein + + + Normal + Normaal + + + Medium + Gemiddeld + + + Large + Groot + + + Custom + Aangepast @@ -280,25 +312,6 @@ Include beta releases when checking for updates Ook zoeken naar bètaversies - - On database unlock, show entries that - Na het ontgrendelen van een database: items tonen die - - - have expired - On database unlock, show entries that... - zijn verlopen - - - days - On database unlock, show entries that will expire within %1 days - dagen - - - will expire within - On database unlock, show entries that... - zullen verlopen in - File Management Bestandsbeheer @@ -323,33 +336,21 @@ Backup database file before saving Reservekopie van database maken alvorens op te slaan - - Backup destination - Bestemming van de reservekopie - - - Specifies the database backup file location. Occurrences of "{DB_FILENAME}" are replaced with the filename of the saved database without extension. {TIME:<format>} is replaced with the backup time, see https://doc.qt.io/qt-5/qdatetime.html#toString. <format> defaults to format string "dd_MM_yyyy_hh-mm-ss". - Hier kun je de locatie van het reservekopiebestand van de database opgeven. Items met "{DB_FILENAME}" worden vervangen door de bestandsnaam van de opgeslagen database, zonder de extensie. {TIME:<format>} wordt vervangen door de reservekopietijd (zie https://doc.qt.io/qt-5/qdatetime.html#toString). <format> is de standaard tekenreeks ‘dd_MM_yyyy_hh-mm-ss’. - {DB_FILENAME}.old.kdbx {DB_FILENAME}.oud.kdbx - - Choose... - Kiezen… - Use alternative saving method (may solve problems with Dropbox, Google Drive, GVFS, etc.) Alternatieve opslagmethode gebruiken (kan problemen oplossen met Dropbox, Google Drive, GVFS, etc.) Temporary file moved into place - Het tijdelijke bestand is op zijn plaats gezet + Tijdelijk bestand verplaatst naar zijn plaats Directly write to database file (dangerous) - Direct wegschrijven naar databasebestand (gevaarlijk) + Databasebestand direct overschrijven (gevaarlijk) Entry Management @@ -410,7 +411,7 @@ (restart program to activate) - (herstart om de wijziging toe te passen) + (opnieuw starten om te activeren) Toolbar button style: @@ -430,7 +431,7 @@ Show a system tray icon - Pictogram tonen in systeemvak + Pictogram weergeven in systeemvak Tray icon type @@ -462,7 +463,7 @@ Always ask before performing Auto-Type - Altijd vragen alvorens automatisch in te vullen + Altijd vragen voor automatisch invullen Hide expired entries from Auto-Type @@ -474,15 +475,15 @@ Auto-Type start delay: - Wachttijd alvorens automatisch in te vullen: + Wachttijd bij automatisch invullen: Global Auto-Type shortcut: - Algemene sneltoets van automatisch invullen: + Algemene sneltoets voor automatisch invullen: Auto-type start delay milliseconds - Wachttijd alvorens automatisch in te vullen (in milliseconden) + Wachttijd bij automatisch invullen (milliseconden) ms @@ -491,7 +492,7 @@ Auto-Type typing delay: - Wachttijd alvorens automatisch in te vullen: + Wachttijd bij automatisch invullen: Global auto-type shortcut @@ -499,11 +500,76 @@ Auto-type character typing delay milliseconds - Wachttijd alvorens automatisch in te vullen (in milliseconden) + Wachttijd bij automatisch invullen (milliseconden) Remember last typed entry for: - Laatstgebruikt item gebruiken voor: + Laatstgebruikt item onthouden: + + + On database unlock, show entries that will expire within + Bij ontgrendeling van de database; items weergeven die verlopen binnen + + + On database unlock, show entries that will expire within + Bij ontgrendeling van de database; items weergeven die verlopen binnen + + + days + number of days warning for password expiration + dagen + + + Destination format: + Doelformaat: + + + <html><head/><body><p><span style=" font-weight:600;">{DB_FILENAME}</span> is replaced with the filename of the saved database without extension</p><p><span style=" font-weight:600;">{TIME:&lt;format&gt;}</span> is replaced with the specified time format (default: dd_MM_yyyy_hh-mm-ss)</p><p>See the User Guide for more details</p></body></html> + <html><head/><body><p><span style=" font-weight:600;">{DB_FILENAME}</span> wordt vervangen door de bestandsnaam van de opgeslagen database zonder extensie </p><p><span style=" font-weight:600;">{TIME:&lt;format&gt;}</span> wordt vervangen door de gespecifieerde tijdopmaak (standaard: dd_MM_yyyy_hh-mm-ss)</p><p>Lees de gebruikershandleiding voor meer details</p></body></html> + + + Choose folder... + Kies een map… + + + Show confirmation before moving entries to recycle bin + Om bevestiging vragen voordat items worden verplaatst naar de prullenbak + + + Copy data on double clicking field in entry view + Gegevens kopiëren bij dubbelklikken van veld in itemweergave + + + Show toolbar + Werkbalk weergeven + + + Show the menu bar by pressing the Alt key + Werkbalk weergeven met de Alt-toets + + + Show menubar + Menubalk weergeven + + + Import settings… + Instellingen importeren… + + + Export settings… + Instellingen exporteren… + + + Open browser on double clicking URL field in entry view + Browser openen bij dubbelklik op URL-veld in itemweergave + + + Font size: + Lettergrootte + + + Font size selection + Selectie van lettergrootte @@ -568,19 +634,7 @@ Hide passwords in the entry preview panel - Wachtwoorden in voorbeeldvenster verbergen - - - Hide entry notes by default - Notities standaard verbergen - - - Move entries to recycle bin without confirmation - Items zonder bevestiging naar prullenbak verplaatsen - - - Enable double click to copy the username/password entry columns - Dubbelklikken inschakelen om de kolommen voor gebruikersnaam/wachtwoordinvoer te kopiëren + Wachtwoorden verbergen in Informatiepaneel Privacy @@ -592,7 +646,19 @@ Hide TOTP in the entry preview panel - TOTP in het voorbeeldvenster verbergen + TOTP verbergen in Informatiepaneel + + + Lock databases when switching user + Databases vergrendelen bij het wisselen van gebruiker + + + Lock Options + Vergrendelingsopties + + + Hide notes in the entry preview panel + Notities verbergen in Informatiepaneel @@ -641,20 +707,6 @@ Entry does not have attribute for PICKCHARS: %1 Het item bevat geen kenmerk voor PICKCHARS: %1 - - Invalid conversion type: %1 - Ongeldig conversietype: %1 - - - Invalid conversion syntax: %1 - Ongeldige conversiesyntaxis: %1 - - - Invalid regular expression syntax %1 -%2 - Ongeldige syntaxis in reguliere uitdrukking ‘%1’ -%2 - Invalid placeholder: %1 Ongeldige tijdelijke aanduiding: %1 @@ -735,11 +787,11 @@ Ctrl+2 - Type password<br/> Ctrl+3 - Type TOTP<br/> Ctrl+4 - Use Virtual Keyboard (Windows Only)</p> <p>Je kunt uitgebreide zoekopdrachten uitvoeren om items in de geopende databases te vinden. De volgende sneltoetsen zijn handig:<br/> -Ctrl + F - Database doorzoeken tonen/verbergen<br/> +Ctrl + F - Database doorzoeken<br/> Ctrl + 1 - Gebruikersnaam invoeren<br/> Ctrl + 2 - Wachtwoord invoeren<br/> Ctrl + 3 - TOTP invoeren<br/> -Ctrl + 4 - Virtueel toetsenbord gebruiken (alleen op Windows)</p> +Ctrl + 4 - Virtueel toetsenbord (alleen Windows)</p> Search all open databases @@ -829,7 +881,7 @@ Ctrl + 4 - Virtueel toetsenbord gebruiken (alleen op Windows)</p>BrowserEntrySaveDialog Ok - OK + Oké Cancel @@ -839,7 +891,7 @@ Ctrl + 4 - Virtueel toetsenbord gebruiken (alleen op Windows)</p>You have multiple databases open. Please select the correct database for saving credentials. Er zijn meerdere databases geopend. -Kies de database waarin de inloggegevens dienen te worden opgeslagen. +Selecteer de database waarin de inloggegevens dienen te worden opgeslagen. KeePassXC - Select Database @@ -886,24 +938,25 @@ Kies de database waarin de inloggegevens dienen te worden opgeslagen. Add to existing entry - + Aan bestaand item toevoegen Existing passkey found. Do you want to register a new passkey for: - + Bestaande passkey gevonden. +Wil je een nieuwe passkey registreren voor: Select the existing passkey and press Update to replace it. - + Selecteer de bestaande passkey en druk op Bijwerken om deze te vervangen. Authenticate passkey credentials for: - + Inloggegevens verifiëren voor passkey: Do you want to register a passkey for: - + Wil je een passkey registreren voor: @@ -988,16 +1041,17 @@ Wil je dit item verwijderen? Register a new passkey to this entry: - + Een nieuwe passkey registreren voor dit item: KeePassXC - Update passkey - + KeePassXC - Passkey bijwerken Entry already has a passkey. Do you want to overwrite the passkey in %1 - %2? - + Item heeft al een passkey. +Wil je de passkey overschrijven in %1 - %2? Register @@ -1022,10 +1076,6 @@ Do you want to overwrite the passkey in %1 - %2? General Algemeen - - Browsers installed as snaps are currently not supported. - Browsers die als snap zijn geïnstalleerd, worden momenteel niet ondersteund. - Enable integration for these browsers: Integratie in de volgende browsers inschakelen: @@ -1061,7 +1111,7 @@ Do you want to overwrite the passkey in %1 - %2? Show a notification when credentials are requested Credentials mean login data requested via browser extension - Melding tonen als er om inloggegevens wordt gevraagd + Melding weergeven als er om inloggegevens wordt gevraagd Request to unlock the database if it is locked @@ -1197,18 +1247,6 @@ Do you want to overwrite the passkey in %1 - %2? Custom extension ID Aangepaste extensie-id - - Due to Snap sandboxing, you must run a script to enable browser integration.<br />You can obtain this script from %1 - Door de Snap-sandboxing moet je een script uitvoeren om browserintegratie mogelijk te maken. <br /> Dit script is te vinden op %1 - - - KeePassXC-Browser is needed for the browser integration to work. <br />Download it for %1 and %2 and %3. %4 - KeePassXC-Browser is nodig om de integratie met de browser te laten werken. <br /> Download deze browserextensie voor %1 en %2 en %3. %4 - - - Please see special instructions for browser extension use below - Raadpleeg onderstaande instructies omtrent het gebruik van de browserextensie - Executable Files Uitvoerbare bestanden @@ -1219,11 +1257,11 @@ Do you want to overwrite the passkey in %1 - %2? Select custom proxy location - Kies een aangepaste proxy-locatie + Selecteer een aangepaste proxy-locatie Select native messaging host folder location - Kies de locatie van de native messaging-hostmap + Selecteer de locatie van de native messaging-hostmap Allow keepassxc-proxy to list all entries with their title, URL and UUID in connected databases. @@ -1251,11 +1289,19 @@ Do you want to overwrite the passkey in %1 - %2? Allows using insecure http://localhost with passkeys for testing purposes. - + Maakt het gebruik van onveilige http://localhost met passkeys mogelijk voor testdoeleinden. Allow using localhost with passkeys - + Het gebruik van localhost toestaan met passkeys + + + KeePassXC-Browser is needed for the browser integration to work. <br />Download it for %1 and %2 and %3. + KeePassXC-Browser is nodig om de integratie met de browser te laten werken. <br /> Download deze browserextensie voor %1 en %2 en %3. + + + Browsers installed using Snap or Flatpak are not supported with exception to Firefox installed using Snap. + Browsers die met Snap of Flatpak zijn geïnstalleerd, worden niet ondersteund, met uitzondering van Firefox die met Snap is geïnstalleerd. @@ -1266,7 +1312,7 @@ Do you want to overwrite the passkey in %1 - %2? Append ' - Clone' to title - ' (duplicaat)' toevoegen aan titel + ' - Duplicaat' toevoegen aan titel Replace username and password with references @@ -1393,12 +1439,26 @@ Do you want to overwrite the passkey in %1 - %2? Failed to parse CSV file: %1 - CSV-bestand kon niet worden verwerkt: %1 + Verwerking CSV-bestand mislukt: %1 Imported from CSV file: %1 Geïmporteerd uit CSV-bestand: %1 + + No Title Selected + Geen titel geselecteerd + + + No title column was selected, entries will be hard to tell apart. +Are you sure you want to import? + Er is geen titelkolom geselecteerd, items zijn zo moeilijk van elkaar te onderscheiden. +Weet je zeker dat je wilt importeren? + + + Tags + Labels + CsvParserModel @@ -1462,6 +1522,14 @@ reservekopie van databestand in %2 Recycle Bin Prullenbak + + Database file read error. + Fout bij het lezen van de database. + + + No file path was provided. + Er is geen bestandspad opgegeven. + DatabaseOpenDialog @@ -1576,7 +1644,7 @@ Als je deze foutmelding niet meer wilt zien, ga dan naar ‘Databaseinstellingen Don't show this warning again - Deze waarschuwing niet meer tonen + Deze waarschuwing niet meer weergeven All files @@ -1588,7 +1656,7 @@ Als je deze foutmelding niet meer wilt zien, ga dan naar ‘Databaseinstellingen Select key file - Kies een sleutelbestand + Selecteer een sleutelbestand Cannot use database file as key file @@ -1604,20 +1672,12 @@ Als je deze foutmelding niet meer wilt zien, ga dan naar ‘Databaseinstellingen Select Key File: - Kies een sleutelbestand: + Selecteer sleutelbestand: <p>In addition to a password, you can use a secret file to enhance the security of your database. This file can be generated in your database's security settings.</p><p>This is <strong>not</strong> your *.kdbx database file!</p> <p>Naast een wachtwoord kun je een geheim bestand gebruiken om de beveiliging van je database te verbeteren. Dit bestand kan worden gegenereerd in de beveiligingsinstellingen van jouw database.</p><p>Dit is <strong>niet</strong> jouw *.kdbx-databasebestand!</p> - - Click to add a key file. - Klik om een sleutelbestand toe te voegen. - - - <a href="#" style="text-decoration: underline">I have a key file</a> - Ik heb een <a href="#" style="text-decoration: underline">sleutelbestand</a> - Use hardware key [Serial: %1] Gebruik hardwaresleutel [Serienummer: %1] @@ -1654,6 +1714,18 @@ Weet je zeker dat je wilt doorgaan met dit bestand? Refresh Hardware Keys Hardwaresleutels vernieuwen + + Click to add a key file. + Klik om een sleutelbestand toe te voegen. + + + <a href="#" style="text-decoration: underline">I have a key file</a> + Ik heb een <a href="#" style="text-decoration: underline">sleutelbestand</a> + + + Hardware keys found, but no slots are configured. + Hardwaresleutels gevonden, echter zonder posities geconfigureerd. + DatabaseSettingWidgetMetaData @@ -1688,6 +1760,22 @@ Weet je zeker dat je wilt doorgaan met dit bestand? Maintenance Onderhoud + + KeeShare + KeeShare + + + Secret Service Integration + Integratie met Secret Service + + + Remote Sync + Synchronisatie op afstand + + + Database Settings: %1 + Database-instellingen: %1 + DatabaseSettingsWidgetBrowser @@ -1717,7 +1805,7 @@ Weet je zeker dat je wilt doorgaan met dit bestand? Remove selected key - Gekozen sleutel verwijderen + Geselecteerde sleutel verwijderen Remove @@ -1725,7 +1813,7 @@ Weet je zeker dat je wilt doorgaan met dit bestand? Delete the selected key? - Gekozen sleutel verwijderen? + Geselecteerde sleutel verwijderen? Do you really want to delete the selected key? @@ -1797,7 +1885,7 @@ Dit is alleen nodig als je database een kopie is van een andere en de browserext Convert legacy KeePassHTTP attributes to KeePassXC-Browser compatible custom data - Converteer verouderde KeePassHTTP-kenmerken naar KeePassXC-Browser-compatibele aangepaste gegevens + Converteer verouderde KeePassHTTP-kenmerken naar KeePassXC-Browser-compatibele gegevens No keys found @@ -1858,14 +1946,14 @@ Weet je zeker dat je wilt doorgaan zonder wachtwoord? Weak password Zwak wachtwoord - - You must enter a stronger password to protect your database. - Je moet een sterker wachtwoord invoeren om je database te beschermen. - This is a weak password! For better protection of your secrets, you should choose a stronger password. Dit is een zwak wachtwoord! Voor een betere bescherming van jouw geheimen moet je een sterker wachtwoord kiezen. + + The provided password does not meet the minimum quality requirement. + Het opgegeven wachtwoord voldoet niet aan de minimale kwaliteitseisen. + DatabaseSettingsWidgetEncryption @@ -2122,7 +2210,7 @@ elementen in de geschiedenis bewaard blijft. Limit the amount of history items per entry to: - Beperk het aantal geschiedenisitems per item tot: + Aantal geschiedenisitems per item beperken tot: When saving this setting or editing an entry @@ -2137,7 +2225,7 @@ maximaal de gespecificeerde hoeveelheid bedraagt. Limit the total size of history items per entry to: - Beperk de totale grootte van geschiedenisitems per item tot: + Totale grootte van geschiedenisitems per item beperken tot: Move entries to a recycle bin group @@ -2169,6 +2257,50 @@ worden uit de database verwijderd. Autosave delay since last change checkbox Vertraging bij automatisch opslaan sinds laatste wijziging (selectievakje) + + Public Database Metadata + Openbare database-metagegevens + + + Warning: the following settings are not encrypted. + Let op: de volgende instellingen zijn niet versleuteld. + + + Display name: + Weergavenaam: + + + Publically visible display name used on the unlock dialog + Openbaar zichtbare weergavenaam gebruikt in het dialoogvenster Ontgrendelen + + + Database public display name + Openbaar zichtbare databasenaam + + + Display color: + Weergavekleur: + + + Publically visible color used on the unlock dialog + Openbaar zichtbare kleur gebruikt in het dialoogvenster Ontgrendelen + + + Database public display color chooser + Openbaar zichtbare databasekleur kiezen + + + Clear + Wissen + + + Display icon: + Weergavepictogram: + + + Select Database Icon + Databasepictogram kiezen + DatabaseSettingsWidgetKeeShare @@ -2264,6 +2396,141 @@ worden uit de database verwijderd. Database-omschrijvingveld + + DatabaseSettingsWidgetRemote + + Sync Commands + Synchronisatieopdrachten + + + Remove + Verwijderen + + + Command Settings + Opdrachtinstellingen + + + Name + Naam + + + Save + Opslaan + + + Download + Downloaden + + + Command: + Opdracht: + + + Download command field + Download-opdrachtveld + + + e.g.: "sftp user@hostname" or "scp user@hostname:DatabaseOnRemote.kdbx {TEMP_DATABASE}" + bv.: "sftp user@hostname" of "scp user@hostname:DatabaseOnRemote.kdbx {TEMP_DATABASE}" + + + Input: + Invoer: + + + Download input field + Download-invoerveld + + + Upload + Uploaden + + + Upload command field + Upload-opdrachtveld + + + e.g.: "sftp user@hostname" or "scp {TEMP_DATABASE} user@hostname:DatabaseOnRemote.kdbx" + bv.: "sftp user@hostname" of "scp {TEMP_DATABASE} user@hostname:DatabaseOnRemote.kdbx" + + + Upload input field + Upload-invoerveld + + + Name cannot be empty. + Naam kan niet leeg zijn. + + + Test + Testen + + + Download command cannot be empty. + Downloadopdracht kan niet leeg zijn. + + + Download failed with error: %1 + Download is mislukt met fout: %1 + + + Download finished, but file %1 could not be found. + Download is klaar, maar bestand %1 is niet gevonden. + + + Download successful. + Download succesvol. + + + Save Remote Settings + Externe instellingen opslaan + + + You have unsaved changes. Do you want to save them? + Er zijn niet-opgeslagen wijzigingen. Wil je deze opslaan? + + + e.g.: +get DatabaseOnRemote.kdbx {TEMP_DATABASE} +exit +--- +{TEMP_DATABASE} is used as placeholder to store the database in a temporary location +The command has to exit. In case of `sftp` as last command `exit` has to be sent + + bijv.: +get DatabaseOnRemote.kdbx {TEMP_DATABASE} +exit +--- +{TEMP_DATABASE} wordt gebruikt als tijdelijke aanduiding om de database op een tijdelijke locatie op te slaan +De opdracht moet worden afgesloten. In het geval van `sftp` moet de laatste opdracht `exit` worden verzonden + + + + e.g.: +put {TEMP_DATABASE} DatabaseOnRemote.kdbx +exit +--- +{TEMP_DATABASE} is used as placeholder to store the database in a temporary location +The command has to exit. In case of `sftp` as last command `exit` has to be sent + + bijv.: +put {TEMP_DATABASE} DatabaseOnRemote.kdbx +exit +--- +{TEMP_DATABASE} wordt gebruikt als tijdelijke aanduiding om de database op een tijdelijke locatie op te slaan +De opdracht moet worden afgesloten. In het geval van `sftp` moet de laatste opdracht `exit` worden verzonden + + + + Timeout: + Time-out: + + + seconds + seconden + + DatabaseTabWidget @@ -2337,6 +2604,11 @@ Dit is zeker een fout, rapporteer dit aan de ontwikkelaars. Database tab name modifier %1 [vergrendeld] + + %1 [Temporary] + Database tab name modifier + %1 [Tijdelijk] + DatabaseWidget @@ -2358,7 +2630,7 @@ Dit is zeker een fout, rapporteer dit aan de ontwikkelaars. Perform Auto-Type into the previously active window? - Wilt u automatisch invullen gebruiken in het onlangs actieve venster? + Automatisch invullen uitvoeren in het vorige actieve venster? Execute command? @@ -2460,26 +2732,6 @@ Wijzigingen opslaan? File has changed Bestand is gewijzigd - - The database file has changed. Do you want to load the changes? - Het database-bestand is gewijzigd. Wil je de aanpassingen inlezen? - - - Merge Request - Verzoek om samenvoegen - - - The database file has changed and you have unsaved changes. -Do you want to merge your changes? - Het databasebestand is bewerkt en er zijn niet-opgeslagen wijzigingen. -Wil je de wijzigingen samenvoegen? - - - Could not open the new database file while attempting to autoreload. -Error: %1 - Het nieuwe databasebestand is niet geopend bij het automatisch opnieuw laden. -Foutmelding: %1 - Disable safe saves? Veilig opslaan uitschakelen? @@ -2531,6 +2783,86 @@ Veilig opslaan uitschakelen en opnieuw proberen? Database tab name modifier %1 [nieuwe database] + + Remote Sync did not contain any download or upload commands. + Synchronisatie op afstand bevatte geen download- of uploadopdrachten. + + + Remote sync '%1' completed successfully! + Synchronisatie op afstand '%1' met succes voltooid! + + + Remote sync '%1' failed: %2 + Synchronisatie op afstand '%1' mislukt: %2 + + + Error while saving database %1: %2 + Fout bij het opslaan van database %1: %2 + + + Downloading... + Downloaden… + + + Uploading... + Uploaden… + + + Syncing... + Synchroniseren… + + + Remove passkey from entry + Passkey van item verwijderen + + + Do you want to remove the passkey from this entry? + Wil je de passkey van dit item verwijderen? + + + The database file "%1" was modified externally + Het databasebestand "%1" is extern gewijzigd + + + Do you want to load the changes? + Wil je de wijzigingen laden? + + + Reload database + Database opnieuw laden + + + Reloading database… + Database opnieuw laden… + + + Reload canceled + Opnieuw laden geannuleerd + + + Reload successful + Met succes opnieuw geladen + + + Reload pending user action… + Opnieuw laden wacht op actie van gebruiker… + + + The database file "%1" was modified externally.<br>How would you like to proceed?<br><br>Merge all changes<br>Ignore the changes on disk until save<br>Discard unsaved changes + Het databasebestand "%1" is extern gewijzigd.<br>Hoe wil je verder gaan?<br><br>Alle verschillen samenvoegen<br>De wijzigingen op de schijf negeren tot opslaan<br>Niet-opgeslagen wijzigingen negeren + + + The database file "%1" was modified externally.<br>How would you like to proceed?<br><br>Merge all changes then save<br>Overwrite the changes on disk<br>Discard unsaved changes + Het databasebestand "%1" is extern gewijzigd.<br>Hoe wil je verder gaan?<br><br>Alle wijzigingen samenvoegen en opslaan<br>De wijzigingen op de schijf overschrijven<br>Niet-opgeslagen wijzigingen negeren + + + Database file overwritten. + Databasebestand overschreven. + + + Database file on disk cannot be unlocked with current credentials.<br>Enter new credentials and/or present hardware key to continue. + Databasebestand op schijf kan niet worden ontgrendeld met de huidige inloggegevens.<br>Voer nieuwe inloggegevens en/of een hardwaresleutel in om door te gaan. + EditEntryWidget @@ -2582,13 +2914,9 @@ Veilig opslaan uitschakelen en opnieuw proberen? n/a n.v.t. - - (encrypted) - (beveiligd) - Select private key - Kies een persoonlijke sleutel + Selecteer een persoonlijke sleutel Entry history @@ -2618,13 +2946,13 @@ Helaas zijn alle aangebrachte wijzigingen hierdoor verloren gegaan. Auto-Type Validation Error - Fout bij geldigverklaring automatisch invullen + Validatiefout bij Automatisch invullen An error occurred while validating the custom Auto-Type sequence: %1 Would you like to correct it? - Er is een fout opgetreden tijdens de geldigverklaring van de aangepaste invulreeks: + Er is een fout opgetreden bij de validatie van de aangepaste invulreeks: %1 Wil je dit corrigeren? @@ -2632,7 +2960,7 @@ Wil je dit corrigeren? An error occurred while validating the Auto-Type sequence for "%1": %2 Would you like to correct it? - Er is een fout opgetreden tijdens de geldigverklaring van de aangepaste invulreeks ‘%1’: + Er is een fout opgetreden bij de validatie van de aangepaste invulreeks ‘%1’: %2 Wil je dit corrigeren? @@ -2688,6 +3016,10 @@ Wil je dit corrigeren? %n year(s) %n jaar%n jaren + + Failed to decrypt SSH key, ensure password is correct. + Kan SSH-sleutel niet decoderen, zorg ervoor dat het wachtwoord correct is. + EditEntryWidgetAdvanced @@ -2729,7 +3061,7 @@ Wil je dit corrigeren? Toggle attribute protection - Kenmerkbeveiliging wisselen + Kenmerkbescherming wisselen Protect @@ -2737,7 +3069,7 @@ Wil je dit corrigeren? Show a protected attribute - Beschermd kenmerk tonen + Beschermd kenmerk weergeven Reveal @@ -2761,7 +3093,7 @@ Wil je dit corrigeren? Foreground color selection - Keuze voorgrondkleur + Selectie voorgrondkleur Background Color: @@ -2769,7 +3101,7 @@ Wil je dit corrigeren? Background color selection - Keuze achtergrondkleur + Selectie achtergrondkleur @@ -2792,7 +3124,7 @@ Wil je dit corrigeren? Open Auto-Type help webpage - Hulppagina omtrent automatisch invullen openen + Hulppagina over automatisch invullen openen Window Associations @@ -2859,18 +3191,10 @@ Wil je dit corrigeren? Skip Auto-Submit for this entry Automatisch indienen uitschakelen voor dit item - - Only send this setting to the browser for HTTP Auth dialogs. If enabled, normal login forms will not show this entry for selection. - Stuur deze instelling alleen naar de browser voor HTTP Auth-dialoogvensters. Indien ingeschakeld, zullen normale aanmeldingsformulieren dit item niet als keuze tonen. - Use this entry only with HTTP Basic Auth Item alleen gebruiken met HTTP Basic Auth - - Do not send this setting to the browser for HTTP Auth dialogs. If enabled, HTTP Auth dialogs will not show this entry for selection. - Stuur deze instelling niet naar de browser voor HTTP Auth-dialoogvensters. Indien ingeschakeld, zullen HTTP Auth-dialoogvensters dit item niet als keuze tonen. - Do not use this entry with HTTP Basic Auth Item niet gebruiken met HTTP Basic Auth @@ -2893,7 +3217,15 @@ Wil je dit corrigeren? Additional URLs - Extra URL's + Aanvullende URL's + + + Only send this entry to the browser for HTTP Auth dialogs. If enabled, normal login forms will not show this entry for selection. + Stuur deze instelling alleen naar de browser voor HTTP Auth-dialoogvensters. Indien ingeschakeld, zullen normale aanmeldingsformulieren dit item niet als keuze tonen. + + + Do not send this entry to the browser for HTTP Auth dialogs. If enabled, HTTP Auth dialogs will not show this entry for selection. + Stuur deze instelling niet naar de browser voor HTTP Auth-dialoogvensters. Indien ingeschakeld, zullen HTTP Auth-dialoogvensters dit item niet als keuze tonen. @@ -2908,7 +3240,7 @@ Wil je dit corrigeren? Show - Tonen + Weergeven Restore entry to selected history state @@ -3095,7 +3427,7 @@ Wil je dit corrigeren? Select attachment file - Kies een bijlagebestand + Selecteer een bijlagebestand Require user confirmation when this key is used @@ -3117,6 +3449,10 @@ Wil je dit corrigeren? seconds seconden + + Clear agent + Agent wissen + EditGroupWidget @@ -3213,7 +3549,7 @@ Wil je dit corrigeren? Restrict matching to given browser key toggle for this and sub groups - Overeenkomst beperken tot gegeven browsersleutel voor deze en subgroepen + Overeenkomst beperken tot gegeven browsersleutel voor deze en onderliggende groepen @@ -3315,15 +3651,15 @@ Ondersteunde extensies: %1. Select import source - Kies een te importeren bron + Selecteer een te importeren bron Select export target - Kies een exportlocatie + Selecteer een exportlocatie Select import/export file - Kies een im-/exportbestand + Selecteer een im-/exportbestand @@ -3370,7 +3706,7 @@ Ondersteunde extensies: %1. Default auto-type sequence field - Standaard invulreeks + Standaard veld voor automatische invulreeks Notes field @@ -3421,7 +3757,7 @@ Ondersteunde extensies: %1. Apply selected icon to subgroups and entries - Gekozen pictogram toepassen bij onderliggende groepen en items + Geselecteerd pictogram toepassen bij onderliggende groepen en items Apply icon to… @@ -3461,7 +3797,7 @@ Ondersteunde extensies: %1. Select Image(s) - Afbeeldingen selecteren + Afbeelding(en) selecteren Successfully loaded %1 of %n icon(s) @@ -3559,6 +3895,24 @@ Hierdoor werken de plug-ins mogelijk niet goed meer. %1 - Clone %1 - Duplicaat + + Passkey + Passkey + + + Invalid conversion type: %1 + Ongeldig conversietype: %1 + + + Invalid conversion syntax: %1 + Ongeldige conversiesyntaxis: %1 + + + Invalid regular expression syntax %1 +%2 + Ongeldige syntaxis in reguliere expressie %1 +%2 + EntryAttachments @@ -3567,6 +3921,21 @@ Hierdoor werken de plug-ins mogelijk niet goed meer. Bestand ‘%1’ is niet geopend + + EntryAttachmentsDialog + + Form + Formulier + + + File name + Bestandsnaam + + + File contents... + Bestandsinhoud… + + EntryAttachmentsModel @@ -3604,14 +3973,6 @@ Hierdoor werken de plug-ins mogelijk niet goed meer. Remove Verwijderen - - Rename selected attachment - Geselecteerde bijlage hernoemen - - - Rename - Hernoemen - Open selected attachment Geselecteerde bijlage openen @@ -3630,7 +3991,7 @@ Hierdoor werken de plug-ins mogelijk niet goed meer. Select files - Bestanden kiezen + Bestanden selecteren Confirm remove @@ -3725,6 +4086,18 @@ Would you like to overwrite the existing attachment? De bijlage ‘%1’ bestaat al. Wil je de bestaande bijlage overschrijven? + + New + Nieuw + + + Preview + Voorbeeld + + + Failed to preview an attachment: Attachment not found + Geen voorbeeld van bijlage: bijlage niet aangetroffen + EntryAttributesModel @@ -3923,6 +4296,10 @@ Wil je de bestaande bijlage overschrijven? Background Color Achtergrondkleur + + Group Path + Groepspad + EntryPreviewWidget @@ -4131,7 +4508,7 @@ Dit maakt jouw wachtwoorden en gevoelige informatie kwetsbaar! Another secret service is running (%1).<br/>Please stop/remove it before re-enabling the Secret Service Integration. - Er is al een andere Secret Service actief (%1).<br/>Stop/Verwijder deze en probeer de integratie van Secret Service opnieuw in te schakelen. + Er is al een andere Secret Service actief (%1).<br/>Stop/Verwijder deze en probeer de integratie met Secret Service opnieuw in te schakelen. Failed to register DBus service at %1.<br/> @@ -4188,7 +4565,7 @@ Dit maakt jouw wachtwoorden en gevoelige informatie kwetsbaar! FdoSecrets::SettingsDatabaseModel Unlock to show - Ontgrendelen om te bekijken + Ontgrendelen om weer te geven None @@ -4266,7 +4643,7 @@ Je kunt de pictogrammenservice van de DuckDuckGo-website inschakelen in de secti Ok - OK + Oké Already Exists @@ -4318,6 +4695,14 @@ Je kunt de pictogrammenservice van de DuckDuckGo-website inschakelen in de secti Url URL + + Could not load key file. + Kan sleutelbestand niet laden. + + + Could not open remote database. Password or key file may be incorrect. + Kan externe database niet openen. Wachtwoord of sleutelbestand is mogelijk onjuist. + ImportWizardPageSelect @@ -4387,7 +4772,7 @@ Je kunt de pictogrammenservice van de DuckDuckGo-website inschakelen in de secti Select import file - Kies importbestand + Selecteer importbestand All files @@ -4399,7 +4784,7 @@ Je kunt de pictogrammenservice van de DuckDuckGo-website inschakelen in de secti Select key file - Kies sleutelbestand + Selecteer sleutelbestand Comma Separated Values @@ -4421,6 +4806,50 @@ Je kunt de pictogrammenservice van de DuckDuckGo-website inschakelen in de secti KeePass1 Database KeePass 1-database + + Proton Pass (.json) + Proton Pass (.json) + + + Proton Pass JSON Export + Proton Pass JSON Export + + + Temporary Database + Tijdelijke database + + + Command: + Opdracht: + + + e.g.: "sftp user@hostname" or "scp user@hostname:DatabaseOnRemote.kdbx {TEMP_DATABASE}" + bv.: "sftp user@hostname" of "scp user@hostname:DatabaseOnRemote.kdbx {TEMP_DATABASE}" + + + Input: + Invoer: + + + e.g.: +get DatabaseOnRemote.kdbx {TEMP_DATABASE} +exit +--- +{TEMP_DATABASE} is used as placeholder to store the database in a temporary location +The command has to exit. In case of `sftp` as last commend `exit` has to be sent + + bv.: +get DatabaseOnRemote.kdbx {TEMP_DATABASE} +exit +--- +{TEMP_DATABASE} wordt gebruikt als tijdelijke aanduiding om de database op een tijdelijke locatie op te slaan +De opdracht moet worden afgesloten. In het geval van `sftp` moet `exit` als laatste worden verzonden + + + + Remote Database (.kdbx) + Externe database (.kdbx) + KMessageWidget @@ -4695,7 +5124,7 @@ Als dit nog een keer gebeurt, dan is het databasebestand mogelijk beschadigd. - Het gekozen bestand is een oude KeePass 1-database (.kdb). + Het geselecteerde bestand is een oude KeePass 1-database (.kdb). Je kan de database importeren via Database → ‘KeePass 1-database importeren’. Let op: deze actie is onomkeerbaar. De geïmporteerde database kan niet meer worden geopend met de oude KeePassX-versie 0.4. @@ -5112,7 +5541,7 @@ Als dit nog een keer gebeurt, dan is het databasebestand mogelijk beschadigd. You selected a key file in an old format which KeePassXC<br>may stop supporting in the future.<br><br>Please consider generating a new key file instead. - Je hebt een sleutelbestand in een oud formaat gekozen dat KeePassXC in de toekomst mogelijk niet meer ondersteunt.<br><br>Overweeg in plaats daarvan een nieuw sleutelbestand te genereren. + Je hebt een sleutelbestand in een oud formaat geselecteerd dat KeePassXC in de toekomst mogelijk niet meer ondersteunt.<br><br>Overweeg in plaats daarvan een nieuw sleutelbestand te genereren. Error loading the key file '%1' @@ -5166,7 +5595,7 @@ Bericht: %2 Select a key file - Kies een sleutelbestand + Selecteer een sleutelbestand Invalid Key File @@ -5418,11 +5847,11 @@ Weet je zeker dat je dit bestand wilt gebruiken? Show TOTP - TOTP tonen + TOTP weergeven Show QR Code - TOTP QR-code tonen + TOTP QR-code weergeven Set up TOTP… @@ -5458,7 +5887,7 @@ Weet je zeker dat je dit bestand wilt gebruiken? &Online Help - &Online hulp + &Online hulp (EN) &User Guide @@ -5470,7 +5899,7 @@ Weet je zeker dat je dit bestand wilt gebruiken? &Keyboard Shortcuts - &Sneltoetsen + &Sneltoetsen (EN) Save Database Backup… @@ -5486,7 +5915,7 @@ Weet je zeker dat je dit bestand wilt gebruiken? Compact Mode - Compacte weergave + Compacte modus Automatic @@ -5510,11 +5939,11 @@ Weet je zeker dat je dit bestand wilt gebruiken? Show Toolbar - Werkbalk tonen + Werkbalk weergeven Show Preview Panel - Voorbeeldvenster tonen + Informatiepaneel weergeven Always on Top @@ -5561,12 +5990,6 @@ Deze versie is niet bedoeld voor dagelijks gebruik. Expect some bugs and minor issues, this version is meant for testing purposes. LET OP: je maakt gebruik van een pre-release versie van KeePassXC! Houd rekening met fouten en kleine problemen. Deze versie is bedoeld voor testdoeleinden. - - - WARNING: Your Qt version may cause KeePassXC to crash with an On-Screen Keyboard. -We recommend you use the AppImage available on our downloads page. - WAARSCHUWING: jouw Qt-versie kan ervoor zorgen dat KeePassXC crasht met een schermtoetsenbord! -We raden je aan de AppImage te gebruiken die beschikbaar is op onze downloadpagina. No Tags @@ -5614,7 +6037,7 @@ We raden je aan de AppImage te gebruiken die beschikbaar is op onze downloadpagi You must restart the application to apply this setting. Would you like to restart now? - Je moet de applicatie opnieuw opstarten om deze instelling toe te passen. Wil je nu opnieuw opstarten? + Je moet KeePassXC opnieuw opstarten om deze instelling toe te passen. Wil je dat nu doen? Allow Screen Capture @@ -5640,6 +6063,10 @@ We raden je aan de AppImage te gebruiken die beschikbaar is op onze downloadpagi Import Passkey Passkey importeren + + Remote S&ync… + S&ynchronisatie op afstand… + Quit Application Programma afsluiten @@ -5702,19 +6129,19 @@ We raden je aan de AppImage te gebruiken die beschikbaar is op onze downloadpagi Show Database Security - Databasebeveiliging tonen + Database-beveiliging weergeven Show Database Reports - Databaserapportage tonen + Database-rapportage weergeven Show Database Settings - Database-instellingen tonen + Database-instellingen weergeven Show Passkeys - Passkeys tonen + Passkeys weergeven Clone Entry @@ -5738,31 +6165,35 @@ We raden je aan de AppImage te gebruiken die beschikbaar is op onze downloadpagi Show Application Settings - Programma-instellingen tonen + Programma-instellingen weergeven Show Password Generator - Wachtwoordgenerator tonen + Wachtwoordgenerator weergeven + + + Remove Passkey From Entry + Passkey van item verwijderen Perform Auto-Type: {USERNAME} - Auto-type uitvoeren: {USERNAME} + Automatisch invullen: {USERNAME} Perform Auto-Type: {USERNAME}{ENTER} - Auto-type uitvoeren: {USERNAME}{ENTER} + Automatisch invullen: {USERNAME}{ENTER} Perform Auto-Type: {PASSWORD} - Auto-type uitvoeren: {PASSWORD} + Automatisch invullen: {PASSWORD} Perform Auto-Type: {PASSWORD}{ENTER} - Auto-type uitvoeren: {PASSWORD}{ENTER} + Automatisch invullen: {PASSWORD}{ENTER} Perform Auto-Type: {TOTP} - Auto-type uitvoeren: {TOTP} + Automatisch invullen: {TOTP} Copy Title @@ -5798,7 +6229,7 @@ We raden je aan de AppImage te gebruiken die beschikbaar is op onze downloadpagi Show TOTP QR Code - TOTP QR-code tonen + TOTP QR-code weergeven Set up TOTP @@ -5838,7 +6269,7 @@ We raden je aan de AppImage te gebruiken die beschikbaar is op onze downloadpagi Toggle Compact Mode - Compacte weergave wisselen + Compacte modus wisselen Set Theme: Automatic @@ -5858,7 +6289,7 @@ We raden je aan de AppImage te gebruiken die beschikbaar is op onze downloadpagi Toggle Show Menubar - Menubalk-weergave wisselen + Menubalk tonen/verbergen Toggle Show Toolbar @@ -5866,7 +6297,7 @@ We raden je aan de AppImage te gebruiken die beschikbaar is op onze downloadpagi Toggle Show Preview Panel - Voorbeeldvenster tonen/verbergen + Informatiepaneel tonen/verbergen Toggle Always on Top @@ -5874,11 +6305,11 @@ We raden je aan de AppImage te gebruiken die beschikbaar is op onze downloadpagi Toggle Hide Usernames - Gebruikersnaam tonen/verbergen + Gebruikersnamen tonen/verbergen Toggle Hide Passwords - Wachtwoord tonen/verbergen + Wachtwoorden tonen/verbergen Export to XML @@ -5888,6 +6319,34 @@ We raden je aan de AppImage te gebruiken die beschikbaar is op onze downloadpagi Toggle Allow Screen Capture Schermopname toestaan wisselen + + Show Group Panel + Navigatiepaneel weergeven + + + Toggle Show Group Panel + Navigatiepaneel tonen/verbergen + + + Setup Remote Sync… + Synchronisatie op afstand instellen… + + + Password Generator + Wachtwoordgenerator + + + E&xpire Entry… + Item laten verlo&pen… + + + Clear SSH Agent + SSH-agent wissen + + + Clear all identities in ssh-agent + Alle identiteiten in SSH-agent wissen + ManageDatabase @@ -5905,7 +6364,7 @@ We raden je aan de AppImage te gebruiken die beschikbaar is op onze downloadpagi Unlock database to show more information - Ontgrendel de database om meer informatie te tonen + Database ontgrendelen om meer informatie weer te geven Lock database @@ -6038,6 +6497,25 @@ We raden je aan de AppImage te gebruiken die beschikbaar is op onze downloadpagi Geef de nieuwe database een weergavenaam en eventueel een beschrijving: + + NewEntryAttachmentsDialog + + Attachment name cannot be empty + Naam van bijlage kan niet leeg zijn + + + Attachment with the same name already exists + Er bestaat al een bijlage met dezelfde naam + + + Save attachment + Bijlage opslaan + + + New entry attachment + Nieuwe bijlage bij item + + NixUtils @@ -6191,7 +6669,7 @@ We raden je aan de AppImage te gebruiken die beschikbaar is op onze downloadpagi Unexpected EOF while reading key - Onverwacht bestandseinde bij lezen sleutel + Onverwachte EOF bij lezen sleutel Unsupported key part @@ -6199,7 +6677,7 @@ We raden je aan de AppImage te gebruiken die beschikbaar is op onze downloadpagi Unexpected EOF while reading public key - Onverwacht bestandseinde bij lezen openbare sleutel + Onverwachte EOF bij lezen openbare sleutel Unknown key type: %1 @@ -6207,7 +6685,7 @@ We raden je aan de AppImage te gebruiken die beschikbaar is op onze downloadpagi Unexpected EOF while reading private key - Onverwacht bestandseinde bij persoonlijke sleutel + Onverwachte EOF bij persoonlijke sleutel Can't write public key as it is empty @@ -6215,7 +6693,7 @@ We raden je aan de AppImage te gebruiken die beschikbaar is op onze downloadpagi Unexpected EOF when writing public key - Onverwacht bestandseinde bij schrijven openbare sleutel + Onverwachte EOF bij schrijven openbare sleutel Can't write private key as it is empty @@ -6223,7 +6701,11 @@ We raden je aan de AppImage te gebruiken die beschikbaar is op onze downloadpagi Unexpected EOF when writing private key - Onverwacht bestandseinde bij schrijven persoonlijke sleutel + Onverwachte EOF bij schrijven persoonlijke sleutel + + + (encrypted) + (versleuteld) @@ -6273,7 +6755,7 @@ We raden je aan de AppImage te gebruiken die beschikbaar is op onze downloadpagi Export the following passkey entries. - + De volgende passkey items exporteren: @@ -6347,15 +6829,15 @@ Wil je het overschrijven? Import the following passkey: - + De volgende passkey importeren: Import the following passkey to this entry: - + De volgende passkeys importeren naar dit item: Default passkeys group (Imported Passkeys) - + Standaardgroep voor passkeys (Imported Passkeys) @@ -6378,25 +6860,27 @@ Wil je het overschrijven? Open passkey file - + Passkey-bestand openen Cannot import passkey - + Kan passkey niet importeren Cannot import passkey file "%1". Data is missing. - + Kan passkey-bestand "%1" niet importeren. Gegevens ontbreken. Cannot import passkey file "%1". The following data is missing: %2 - + Kan passkey-bestand "%1" niet importeren. +De volgende gegevens ontbreken: +%2 Cannot import passkey file "%1". Private key is missing or malformed. - + Kan passkey-bestand "%1" niet importeren. Persoonlijke sleutel ontbreekt of is ongeldig. @@ -6577,10 +7061,6 @@ The following data is missing: Also choose from: Kies ook uit: - - Excluded characters: "0", "1", "l", "I", "O", "|", "﹒" - Uitgesloten tekens: "0", "1", "l", "I", "O", "|", "﹒" - Exclude look-alike characters Op elkaar lijkende tekens uitsluiten @@ -6605,10 +7085,6 @@ The following data is missing: Word Count: Aantal woorden: - - Character Count: - Aantal tekens: - Word Case: Hoofdlettergebruik: @@ -6621,10 +7097,6 @@ The following data is missing: Add custom wordlist Aangepaste woordenlijst toevoegen - - character - teken - Close Sluiten @@ -6731,6 +7203,22 @@ Wil je deze overschrijven? Special Characters Speciale tekens + + passwordLength + passwordLength + + + Characters: %1 + Karakters: %1 + + + MIXED case + GEmengDe letters + + + Excluded characters: "0", "1", "l", "I", "O", "|", "﹒", "B", "8", "G", "6" + Uitgesloten tekens: "0", "1", "l", "I", "O", "|", "﹒", "B", "8", "G", "6" + PasswordWidget @@ -6798,6 +7286,21 @@ Wil je deze overschrijven? Druk op &Tab tussen de tekens + + PreviewEntryAttachmentsDialog + + Preview entry attachment + Voorbeeld van bijlage bij item + + + No preview available + Geen voorbeeld beschikbaar + + + Image format not supported + Afbeeldingsformaat niet ondersteund + + QMessageBox @@ -7355,7 +7858,7 @@ Wil je deze overschrijven? Show a database's information. - Toon de informatie van een database. + Informatie van een database weergeven. UUID: @@ -7476,10 +7979,6 @@ Wil je deze overschrijven? Invalid word count %1 Ongeldig aantal woorden %1 - - The word list is too small (< 1000 items) - De woordenlijst is te klein (< 1000 items) - Title for the entry. Titel van dit item. @@ -7624,10 +8123,6 @@ Wil je deze overschrijven? Exit interactive mode. Interactieve modus afsluiten. - - Format to use when exporting. Available choices are 'xml' or 'csv'. Defaults to 'xml'. - Formaat om te gebruiken bij het exporteren. Beschikbare keuzes zijn 'XML' of 'CSV'. Standaard ingesteld op 'XML'. - Exports the content of a database to standard output in the specified format. Exporteert de inhoud van een database naar standaarduitvoer in de opgegeven indeling. @@ -7894,19 +8389,19 @@ Beschikbare opdrachten: Show the entry's current TOTP. - Toon de huidige TOTP van het item. + De huidige TOTP van het item weergeven. Show the protected attributes in clear text. - Toon de beschermde kenmerken in tekst. + De beschermde kenmerken in tekst weergeven. Show all the attributes of the entry. - Toon alle kenmerken van het item. + Alle kenmerken van het item weergeven. Show the attachments of the entry. - Toon de bijlagen van het item. + De bijlagen van het item weergeven. Names of the attributes to show. This option can be specified more than once, with each attribute shown one-per-line in the given order. If no attributes are specified, a summary of the default attributes is given. @@ -7918,11 +8413,11 @@ Beschikbare opdrachten: Show an entry's information. - Toon de informatie van een item. + Informatie over een item weergeven. Name of the entry to show. - Naam van de vermelding om te tonen. + Naam van het weer te geven item. ERROR: unknown attribute %1. @@ -8130,7 +8625,7 @@ Kernel: %3 %4 Secret Service Integration - Integratie van Secret Service + Integratie met Secret Service None @@ -8216,18 +8711,6 @@ Kernel: %3 %4 file empty leeg bestand - - malformed string - misvormde tekenreeks - - - missing closing quote - afsluitend aanhalingsteken ontbreekt - - - %1: (row, col) %2,%3 - %1: (rij, col) %2,%3 - AES 256-bit AES 256-bit @@ -8673,12 +9156,88 @@ Deze optie is verouderd, gebruik in plaats daarvan --set-key-file. Sneltoetsen - Unsupported KDF type, cannot decrypt json file - Niet-ondersteund KDF-type, kan json-bestand niet decoderen + Unknown passkeys error + Onbekende fout met passkey - Unknown passkeys error - + Invalid KDF iterations, cannot decrypt json file + Ongeldige KDF-iteraties. Kan json-bestand niet decoderen + + + Unsupported format, ensure your Bitwarden export is password-protected + Niet-ondersteund formaat. Zorg ervoor dat de Bitwarden-export met een wachtwoord is beveiligd + + + Only PBKDF and Argon2 are supported, cannot decrypt json file + Alleen PBKDF en Argon2 worden ondersteund. Kan het json-bestand niet decoderen + + + Reset Shortcuts + Sneltoetsen opnieuw instellen + + + Double click an action to change its shortcut + Dubbelklik op een actie om de sneltoets te wijzigen + + + Filter... + Filteren… + + + Shortcut Conflict + Sneltoetsenconflict + + + Shortcut %1 conflicts with '%2'. Overwrite shortcut? + Sneltoets %1 conflicteert met '%2'. Sneltoets overschrijven? + + + Cannot generate valid passphrases because the wordlist is too short + Kan geen geldige wachtwoordzinnen genereren omdat de woordenlijst te kort is + + + Encrypted files are not supported. + Versleutelde bestanden worden niet ondersteund + + + Proton Pass Import + Proton Pass Import + + + Delete plugin data? + Plugin-gegevens verwijderen? + + + Delete plugin data from Entry(s)? + Plugin-gegevens uit item verwijderen?Plugin-gegevens uit items verwijderen? + + + Passkey + Passkey + + + Format to use when exporting. Available choices are 'xml', 'csv' or 'html'. Defaults to 'xml'. + Toe te passen formaat bij het exporteren. Beschikbare keuzes zijn 'xml', 'csv' of 'html'. Standaard ingesteld op 'xml'. + + + start minimized to the system tray + start geminimaliseerd in het systeemvak + + + malformed string, possible unescaped delimiter + misvormde tekenreeks, mogelijk niet-verwerkt scheidingsteken + + + missing closing delimiter + afsluitend scheidingsteken ontbreekt + + + %1, row: %2, column: %3 + %1, rij: %2, kolom: %3 + + + Tags + Labels @@ -8715,6 +9274,37 @@ Deze optie is verouderd, gebruik in plaats daarvan --set-key-file. Interne zlib-fout: + + RemoteHandler + + Command `%1` did not finish in time. Process was killed. + Opdracht `%1` was niet op tijd klaar. Proces is afgebroken. + + + Failed to upload merged database. Command `%1` did not finish in time. Process was killed. + Kan samengevoegde database niet uploaden. Opdracht `%1` was niet op tijd klaar. Proces is afgebroken. + + + Invalid download parameters provided. + Ongeldige downloadparameters opgegeven. + + + Command `%1` failed to download database. + Opdracht `%1` heeft de database niet gedownload. + + + Invalid database pointer or upload parameters provided. + Ongeldige database-verwijzing of uploadparameters opgegeven. + + + Command `%1` exited with status code: %2 + Opdracht `%1` is afgesloten met statuscode: %2 + + + Failed to upload merged database. Command `%1` exited with status code: %2 + Kan samengevoegde database niet uploaden. Opdracht `%1` is afgesloten met statuscode: %2 + + ReportsWidgetBrowserStatistics @@ -8781,52 +9371,53 @@ Deze optie is verouderd, gebruik in plaats daarvan --set-key-file. Exclude from reports Uitsluiten van rapportage + + Expire Entry(s)… + Item laten verlopen…Items laten verlopen… + Only show entries that have a URL - Toon alleen items met een URL + Alleen items met een URL weergeven Only show entries that have been explicitly allowed or denied - Toon alleen items die expliciet zijn toegestaan of geweigerd + Alleen items weergeven die expliciet zijn toegestaan of geweigerd Show expired entries - Verlopen items tonen + Verlopen items weergeven (Expired) (Verlopen) + + Delete plugin data from Entry(s)… + Plugin-gegevens uit item verwijderen…Plugin-gegevens uit items verwijderen… + ReportsWidgetHealthcheck - Hover over reason to show additional details. Double-click entries to edit. - Positioneer de muis boven een item om aanvullende details weer te geven. Dubbelklik om het te bewerken. + Show expired entries + Verlopen items weergeven - Bad - Password quality - Slecht + (Expired) + (Verlopen) + + + Hover over reason to show additional details. Double-click entries to edit. + Positioneer de muis boven een item om aanvullende details weer te geven. Dubbelklik om het te bewerken. Bad — password must be changed Slecht — wachtwoord moet worden gewijzigd - - Poor - Password quality - Matig - Poor — password should be changed Matig — wachtwoord zou moeten worden gewijzigd - - Weak - Password quality - Zwak - Weak — consider changing the password Zwak — overweeg het wachtwoord te wijzigen @@ -8875,17 +9466,13 @@ Deze optie is verouderd, gebruik in plaats daarvan --set-key-file. Exclude from reports Uitsluiten van rapportage - - Show expired entries - Verlopen items tonen + + Expire Entry(s)… + Item laten verlopen…Items laten verlopen… Show entries that have been excluded from reports - Toon items die zijn uitgesloten van rapporten - - - (Expired) - (Verlopen) + Items die zijn uitgesloten van rapporten weergeven @@ -8900,7 +9487,7 @@ Deze optie is verouderd, gebruik in plaats daarvan --set-key-file. Also show entries that have been excluded from reports - Toon ook vermeldingen die zijn uitgesloten van rapportage + Vermeldingen die zijn uitgesloten van rapportage ook weergeven This build of KeePassXC does not have network functions. Networking is required to check your passwords against Have I Been Pwned databases. @@ -8982,6 +9569,10 @@ Deze optie is verouderd, gebruik in plaats daarvan --set-key-file. Exclude from reports Uitsluiten van rapportage + + Expire Entry(s)… + Item laten verlopen…Items laten verlopen… + ReportsWidgetPasskeys @@ -9027,7 +9618,7 @@ Deze optie is verouderd, gebruik in plaats daarvan --set-key-file. Show expired entries - Verlopen items tonen + Verlopen items weergeven (Expired) @@ -9043,11 +9634,11 @@ Deze optie is verouderd, gebruik in plaats daarvan --set-key-file. Please wait, list of entries with passkeys is being updated… - + Even geduld, de lijst met items met passkeys wordt bijgewerkt… No entries with passkeys. - + Geen items met passkeys. @@ -9223,6 +9814,14 @@ Deze optie is verouderd, gebruik in plaats daarvan --set-key-file. No agent running, cannot list identities. Geen agent actief, kan geen identiteiten opsommen. + + Failed to remove all SSH identities from agent. + Niet alle SSH-identiteiten van de agent verwijderd. + + + All SSH identities removed from agent. + Alle SSH-identiteiten verwijderd van agent. + SearchHelpWidget @@ -9304,7 +9903,7 @@ Deze optie is verouderd, gebruik in plaats daarvan --set-key-file. Limit search to selected group - Beperk het zoeken tot de geselecteerde groep + Zoekopdrachten beperken tot geselecteerde groep @@ -9349,7 +9948,7 @@ Deze optie is verouderd, gebruik in plaats daarvan --set-key-file. Enable KeepassXC Freedesktop.org Secret Service integration - De integratie van KeepassXC Freedesktop.org Secret Service inschakelen + De integratie van KeepassXC met Freedesktop.org Secret Service inschakelen General @@ -9508,29 +10107,6 @@ Deze optie is verouderd, gebruik in plaats daarvan --set-key-file. Exporteren naar %1 - - ShortcutSettingsWidget - - Double click an action to change its shortcut - Dubbelklik op een actie om de sneltoets te wijzigen - - - Shortcut Conflict - Sneltoetsenconflict - - - Filter... - Filteren… - - - Shortcut %1 conflicts with '%2'. Overwrite shortcut? - Sneltoets %1 conflicteert met '%2'. Sneltoets overschrijven? - - - Reset Shortcuts - Sneltoetsen opnieuw instellen - - TagModel @@ -9819,14 +10395,18 @@ Voorbeeld: JBSWY3DPEHPK3PXP No hardware keys detected Geen hardwaresleutels gedetecteerd - - <p>If you own a <a href="https://www.yubico.com/">YubiKey</a> or <a href="https://onlykey.io">OnlyKey</a>, you can use it for additional security.</p><p>The key requires one of its slots to be programmed as <a href="https://docs.yubico.com/yesdk/users-manual/application-otp/challenge-response.html">HMAC-SHA1 Challenge-Response</a>.</p> - <p>Als je een <a href="https://www.yubico.com/">YubiKey</a> of <a href="https://onlykey.io">OnlyKey</a> bezit, kun je deze gebruiken voor extra beveiliging.</p><p>De sleutel vereist dat een van zijn posities (slots) wordt geprogrammeerd als <a href="https://docs.yubico.com/yesdk/users-manual/application-otp/challenge-response.html">HMAC-SHA1 Challenge-Response</a>.</p> - Refresh hardware keys Hardwaresleutels vernieuwen + + <p>If you own a <a href="https://www.yubico.com/">YubiKey</a> or <a href="https://onlykey.io">OnlyKey</a>, you can use it for additional security.</p><p>The key requires one of its slots to be programmed with <a href="https://keepassxc.org/docs/#faq-yubikey-howto">Challenge-Response</a>.</p> + <p>Als je <a href="https://www.yubico.com/">YubiKey</a> of <a href="https://onlykey.io">OnlyKey</a> bezit, dan kan je deze gebruiken voor aanvullende beveiliging.</p><p>Een van de positie in de sleutel moet dan worden geprogrammeerd met <a href="https://keepassxc.org/docs/#faq-yubikey-howto">Challenge-Response</a>.</p> + + + Hardware keys found, but no slots are configured + Hardwaresleutels gevonden, echter zonder posities geconfigureerd. + YubiKeyInterfacePCSC diff --git a/share/translations/keepassxc_pl.ts b/share/translations/keepassxc_pl.ts index f51a7457b..55b9e4b0c 100644 --- a/share/translations/keepassxc_pl.ts +++ b/share/translations/keepassxc_pl.ts @@ -217,18 +217,50 @@ You must restart the application to set the new language. Would you like to restart now? Musisz uruchomić ponownie aplikację, aby ustawić nowy język. Czy chcesz teraz to zrobić? - - Reset Settings? - Zresetować ustawienia? - - - Are you sure you want to reset all general and security settings to default? - Czy na pewno chcesz zresetować wszystkie ustawienia ogólne i zabezpieczeń do domyślnych? - Select backup storage directory Wybierz katalog przechowywania kopii zapasowych + + Confirm Reset + Potwierdź resetowanie + + + Are you sure you want to reset all settings to default? + Czy na pewno chcesz przywrócić wszystkie ustawienia domyślne? + + + Import KeePassXC Settings + Importuj ustawienia KeePassXC + + + Failed to import settings from %1, not a valid settings file. + Nie udało się zaimportować ustawień z %1. To nie jest prawidłowy plik ustawień. + + + Export KeePassXC Settings + Eksportuj ustawienia KeePassXC + + + Small + Mały + + + Normal + Normalny + + + Medium + Średni + + + Large + Duży + + + Custom + Niestandardowy + ApplicationSettingsWidgetGeneral @@ -280,25 +312,6 @@ Include beta releases when checking for updates Uwzględnij wersje beta podczas sprawdzania aktualizacji - - On database unlock, show entries that - Po odblokowaniu bazy danych pokaż wpisy, które - - - have expired - On database unlock, show entries that... - wygasły - - - days - On database unlock, show entries that will expire within %1 days - dni - - - will expire within - On database unlock, show entries that... - wygasną w ciągu - File Management Zarządzanie plikami @@ -317,28 +330,16 @@ Automatically reload the database when modified externally - Automatycznie przeładuj bazę danych, gdy zostanie zmodyfikowana zewnętrznie + Automatycznie ładuj ponownie bazę danych, gdy zostanie zmodyfikowana zewnętrznie Backup database file before saving Utwórz kopię zapasową pliku bazy danych przed zapisaniem - - Backup destination - Miejsce docelowe kopii zapasowej - - - Specifies the database backup file location. Occurrences of "{DB_FILENAME}" are replaced with the filename of the saved database without extension. {TIME:<format>} is replaced with the backup time, see https://doc.qt.io/qt-5/qdatetime.html#toString. <format> defaults to format string "dd_MM_yyyy_hh-mm-ss". - Określa lokalizację pliku kopii zapasowej bazy danych. Wystąpienia "{DB_FILENAME}" są zastępowane nazwą pliku zapisanej bazy danych bez rozszerzenia. {TIME:<format>} jest zastępowany czasem kopii zapasowej, zobacz https://doc.qt.io/qt-5/qdatetime.html#toString. <format> to domyślnie ciąg formatu "dd_MM_yyyy_hh-mm-ss". - {DB_FILENAME}.old.kdbx {DB_FILENAME}.old.kdbx - - Choose... - Wybierz... - Use alternative saving method (may solve problems with Dropbox, Google Drive, GVFS, etc.) Użyj alternatywnej metody zapisywania (może rozwiązać problemy z usługami: Dropbox, Google Drive, GVFS itp.) @@ -442,7 +443,7 @@ Hide window to system tray when minimized - Schowaj okno do zasobnika podczas minimalizacji + Schowaj okno do zasobnika systemowego podczas minimalizacji Reset settings to default… @@ -505,6 +506,71 @@ Remember last typed entry for: Pamiętaj ostatnio wpisany wpis przez: + + On database unlock, show entries that will expire within + Podczas odblokowania bazy danych pokaż wpisy, które wygasną w ciągu + + + On database unlock, show entries that will expire within + Podczas odblokowania bazy danych pokaż wpisy, które wygasną w ciągu + + + days + number of days warning for password expiration + dni + + + Destination format: + Format docelowy: + + + <html><head/><body><p><span style=" font-weight:600;">{DB_FILENAME}</span> is replaced with the filename of the saved database without extension</p><p><span style=" font-weight:600;">{TIME:&lt;format&gt;}</span> is replaced with the specified time format (default: dd_MM_yyyy_hh-mm-ss)</p><p>See the User Guide for more details</p></body></html> + <html><head/><body><p><span style=" font-weight:600;">{DB_FILENAME}</span> zostaje zastąpiony nazwą pliku zapisanej bazy danych bez rozszerzenia</p><p><span style=" font-weight:600;">{TIME:&lt;format&gt;}</span> zostaje zastąpiony określonym formatem czasu (domyślnie: dd_MM_yyyy_hh-mm-ss)</p><p>Więcej szczegółów znajdziesz w podręczniku użytkownika</p></body></html> + + + Choose folder... + Wybierz folder... + + + Show confirmation before moving entries to recycle bin + Pokaż potwierdzenie przed przeniesieniem wpisów do kosza + + + Copy data on double clicking field in entry view + Kopiuj dane po dwukrotnym kliknięciu pola w widoku wpisu + + + Show toolbar + Pokaż pasek narzędzi + + + Show the menu bar by pressing the Alt key + Pokaż pasek menu po naciśnięciu klawisza Alt + + + Show menubar + Pokaż pasek menu + + + Import settings… + Importuj ustawienia… + + + Export settings… + Eksportuj ustawienia… + + + Open browser on double clicking URL field in entry view + Otwórz przeglądarkę po dwukrotnym kliknięciu pola adresu URL w widoku wpisu + + + Font size: + Rozmiar czcionki: + + + Font size selection + Wybór rozmiaru czcionki + ApplicationSettingsWidgetSecurity @@ -570,18 +636,6 @@ Hide passwords in the entry preview panel Ukryj hasła w panelu podglądu wpisu - - Hide entry notes by default - Domyślnie ukrywaj wpisy notatek - - - Move entries to recycle bin without confirmation - Przenieś wpisy do kosza bez potwierdzenia - - - Enable double click to copy the username/password entry columns - Włącz podwójne kliknięcie, aby kopiować kolumny wpisów nazwy użytkownika i hasła - Privacy Prywatność @@ -594,6 +648,18 @@ Hide TOTP in the entry preview panel Ukryj TOTP w panelu podglądu wpisu + + Lock databases when switching user + Zablokuj bazy danych podczas zmiany użytkownika + + + Lock Options + Opcje blokowania + + + Hide notes in the entry preview panel + Ukryj notatki w panelu podglądu wpisu + AutoType @@ -641,20 +707,6 @@ Entry does not have attribute for PICKCHARS: %1 Wpis nie ma atrybutu dla PICKCHARS: %1 - - Invalid conversion type: %1 - Nieprawidłowy typ konwersji: %1 - - - Invalid conversion syntax: %1 - Nieprawidłowa składnia konwersji: %1 - - - Invalid regular expression syntax %1 -%2 - Nieprawidłowa składnia wyrażenia regularnego %1 -%2 - Invalid placeholder: %1 Nieprawidłowy symbol zastępczy: %1 @@ -725,7 +777,7 @@ Double click a row to perform Auto-Type or find an entry using the search: - Kliknij dwukrotnie wiersz, aby wykonać autowpisywanie lub znajdź wpis za pomocą wyszukiwania: + Kliknij dwukrotnie wiersz, aby wykonać autowpisywanie, lub znajdź wpis za pomocą wyszukiwania: <p>You can use advanced search queries to find any entry in your open databases. The following shortcuts are useful:<br/> @@ -886,24 +938,25 @@ Wybierz właściwą bazę danych do zapisania danych uwierzytelniających. Add to existing entry - + Dodaj do istniejącego wpisu Existing passkey found. Do you want to register a new passkey for: - + Znaleziono istniejący klucz dostępu. +Czy chcesz zarejestrować nowy klucz dostępu dla: Select the existing passkey and press Update to replace it. - + Wybierz istniejący klucz dostępu i naciśnij przycisk Zaktualizuj, aby go zastąpić. Authenticate passkey credentials for: - + Uwierzytelnij dane uwierzytelniające klucza dostępu dla: Do you want to register a passkey for: - + Czy chcesz zarejestrować klucz dostępu dla: @@ -988,16 +1041,17 @@ Czy chcesz usunąć wpis? Register a new passkey to this entry: - + Zarejestruj nowy klucz dostępu do tego wpisu: KeePassXC - Update passkey - + KeePassXC - Zaktualizuj klucz dostępu Entry already has a passkey. Do you want to overwrite the passkey in %1 - %2? - + Wpis ma już klucz dostępu. +Czy chcesz zastąpić klucz dostępu w %1 - %2? Register @@ -1012,7 +1066,7 @@ Do you want to overwrite the passkey in %1 - %2? This is required for accessing your databases with KeePassXC-Browser - Wymagane jest to aby uzyskać dostęp do baz danych za pomocą KeePassXC-Browser + Wymagane jest to, aby uzyskać dostęp do baz danych za pomocą KeePassXC-Browser Enable browser integration @@ -1022,10 +1076,6 @@ Do you want to overwrite the passkey in %1 - %2? General Ogólne - - Browsers installed as snaps are currently not supported. - Przeglądarki zainstalowane jako snapy są obecnie nieobsługiwane. - Enable integration for these browsers: Włącz integrację z tymi przeglądarkami: @@ -1197,18 +1247,6 @@ Do you want to overwrite the passkey in %1 - %2? Custom extension ID Identyfikator niestandardowego rozszerzenia - - Due to Snap sandboxing, you must run a script to enable browser integration.<br />You can obtain this script from %1 - Ze względu na sandboxing Snap należy uruchomić skrypt, aby umożliwić integrację z przeglądarką.<br />Możesz uzyskać ten skrypt z %1 - - - KeePassXC-Browser is needed for the browser integration to work. <br />Download it for %1 and %2 and %3. %4 - KeePassXC-Browser jest niezbędny do integracji z przeglądarką. <br />Pobierz go dla %1 oraz %2 i %3. %4 - - - Please see special instructions for browser extension use below - Zobacz poniżej specjalne instrukcje dotyczące używania rozszerzenia przeglądarki - Executable Files Pliki wykonywalne @@ -1251,11 +1289,19 @@ Do you want to overwrite the passkey in %1 - %2? Allows using insecure http://localhost with passkeys for testing purposes. - + Umożliwia używanie niezabezpieczonego http://localhost z kluczami dostępu do celów testowych. Allow using localhost with passkeys - + Zezwalaj na używanie localhost z kluczami dostępu + + + KeePassXC-Browser is needed for the browser integration to work. <br />Download it for %1 and %2 and %3. + KeePassXC-Browser jest niezbędny do integracji z przeglądarką. <br />Pobierz go dla %1 oraz %2 i %3. + + + Browsers installed using Snap or Flatpak are not supported with exception to Firefox installed using Snap. + Przeglądarki zainstalowane przy użyciu pakietów Snap lub Flatpak nie są obsługiwane, z wyjątkiem przeglądarki Firefox zainstalowanej przy użyciu pakietu Snap. @@ -1389,7 +1435,7 @@ Do you want to overwrite the passkey in %1 - %2? [%n more message(s) skipped] - [%n więcej komunikat pominięto] [%n więcej komunikatów pominięto] [%n więcej komunikatów pominięto] [%n więcej komunikatów pominięto] + [%n kolejny komunikat pominięto][%n kolejne komunikaty pominięto][%n kolejnych komunikatów pominięto][%n kolejnych komunikatów pominięto] Failed to parse CSV file: %1 @@ -1399,6 +1445,20 @@ Do you want to overwrite the passkey in %1 - %2? Imported from CSV file: %1 Zaimportowano z pliku CSV: %1 + + No Title Selected + Nie wybrano tytułu + + + No title column was selected, entries will be hard to tell apart. +Are you sure you want to import? + Nie wybrano kolumny tytułu, wpisy będą trudne do odróżnienia. +Czy na pewno chcesz importować? + + + Tags + Tagi + CsvParserModel @@ -1462,6 +1522,14 @@ Zapasowa baza danych znajduje się w %2 Recycle Bin Kosz + + Database file read error. + Błąd odczytu pliku bazy danych. + + + No file path was provided. + Nie podano ścieżki dostępu do pliku. + DatabaseOpenDialog @@ -1610,14 +1678,6 @@ Aby zapobiec pojawianiu się tego błędu, musisz przejść do "Ustawienia <p>In addition to a password, you can use a secret file to enhance the security of your database. This file can be generated in your database's security settings.</p><p>This is <strong>not</strong> your *.kdbx database file!</p> <p>Oprócz hasła głównego można użyć pliku sekretnego w celu zwiększenia bezpieczeństwa bazy danych. Ten plik można wygenerować w ustawieniach zabezpieczeń bazy danych.</p><p>To <strong>nie</strong> jest plik bazy danych *. kdbx!</p> - - Click to add a key file. - Kliknij, aby dodać plik klucza. - - - <a href="#" style="text-decoration: underline">I have a key file</a> - <a href="#" style="text-decoration: underline">Mam plik klucza</a> - Use hardware key [Serial: %1] Użyj klucza sprzętowego [Numer seryjny: %1] @@ -1654,6 +1714,18 @@ Czy na pewno chcesz kontynuować z tym plikiem? Refresh Hardware Keys Odśwież klucze sprzętowe + + Click to add a key file. + Kliknij, aby dodać plik klucza. + + + <a href="#" style="text-decoration: underline">I have a key file</a> + <a href="#" style="text-decoration: underline">Mam plik klucza</a> + + + Hardware keys found, but no slots are configured. + Znaleziono klucze sprzętowe, ale nie skonfigurowano żadnych gniazd. + DatabaseSettingWidgetMetaData @@ -1688,6 +1760,22 @@ Czy na pewno chcesz kontynuować z tym plikiem? Maintenance Konserwacja + + KeeShare + KeeShare + + + Secret Service Integration + Integracja z usługą sekretną + + + Remote Sync + Zdalna synchronizacja + + + Database Settings: %1 + Ustawienia bazy danych: %1 + DatabaseSettingsWidgetBrowser @@ -1858,14 +1946,14 @@ Czy na pewno chcesz kontynuować bez hasła? Weak password Słabe hasło - - You must enter a stronger password to protect your database. - Aby chronić bazę danych, musisz wprowadzić silniejsze hasło. - This is a weak password! For better protection of your secrets, you should choose a stronger password. To jest słabe hasło! Aby lepiej chronić swoje sekrety, należy wybrać silniejsze hasło. + + The provided password does not meet the minimum quality requirement. + Podane hasło nie spełnia minimalnych wymagań jakościowych. + DatabaseSettingsWidgetEncryption @@ -2167,6 +2255,50 @@ z kosza są usuwane z bazy danych. Autosave delay since last change checkbox Pole wyboru opóźnienia autozapisu od ostatniej zmian + + Public Database Metadata + Publiczne metadane bazy danych + + + Warning: the following settings are not encrypted. + Ostrzeżenie: poniższe ustawienia nie są szyfrowane. + + + Display name: + Wyświetlana nazwa: + + + Publically visible display name used on the unlock dialog + Publicznie widoczna wyświetlana nazwa używana w oknie dialogowym odblokowywania + + + Database public display name + Wyświetlana nazwa publiczna bazy danych + + + Display color: + Wyświetlany kolor: + + + Publically visible color used on the unlock dialog + Publicznie widoczny kolor używany w oknie dialogowym odblokowywania + + + Database public display color chooser + Selektor wyświetlanego koloru publicznego bazy danych + + + Clear + Wyczyść + + + Display icon: + Wyświetlana ikona: + + + Select Database Icon + Wybierz ikonę bazy danych + DatabaseSettingsWidgetKeeShare @@ -2262,6 +2394,141 @@ z kosza są usuwane z bazy danych. Pole opisu bazy danych + + DatabaseSettingsWidgetRemote + + Sync Commands + Polecenia synchronizacji + + + Remove + Usuń + + + Command Settings + Ustawienia poleceń + + + Name + Nazwa + + + Save + Zapisz + + + Download + Pobierz + + + Command: + Polecenie: + + + Download command field + Pole polecenia pobierania + + + e.g.: "sftp user@hostname" or "scp user@hostname:DatabaseOnRemote.kdbx {TEMP_DATABASE}" + np.: "sftp użytkownik@nazwahosta" lub "scp użytkownik@nazwahosta:ZdalnaBazaDanych.kdbx {TEMP_DATABASE}" + + + Input: + Wejście: + + + Download input field + Pole wejścia pobierania + + + Upload + Wyślij + + + Upload command field + Pole polecenia wysyłania + + + e.g.: "sftp user@hostname" or "scp {TEMP_DATABASE} user@hostname:DatabaseOnRemote.kdbx" + np.: "sftp użytkownik@nazwahosta" lub "scp {TEMP_DATABASE} użytkownik@nazwahosta:ZdalnaBazaDanych.kdbx" + + + Upload input field + Pole wejścia wysyłania + + + Name cannot be empty. + Nazwa nie może być pusta. + + + Test + Testuj + + + Download command cannot be empty. + Polecenie pobierania nie może być puste. + + + Download failed with error: %1 + Pobieranie nie powiodło się z błędem: %1 + + + Download finished, but file %1 could not be found. + Pobieranie zostało zakończone, ale nie można znaleźć pliku %1. + + + Download successful. + Pobieranie powiodło się. + + + Save Remote Settings + Zapisz ustawienia zdalne + + + You have unsaved changes. Do you want to save them? + Masz niezapisane zmiany. Czy chcesz je zapisać? + + + e.g.: +get DatabaseOnRemote.kdbx {TEMP_DATABASE} +exit +--- +{TEMP_DATABASE} is used as placeholder to store the database in a temporary location +The command has to exit. In case of `sftp` as last command `exit` has to be sent + + np.: +get ZdalnaBazaDanych.kdbx {TEMP_DATABASE} +exit +--- +{TEMP_DATABASE} służy jako symbol zastępczy do przechowywania bazy danych w tymczasowej lokalizacji +Polecenie musi się zakończyć. W przypadku `sftp` jako ostatniego polecenia należy wysłać `exit` + + + + e.g.: +put {TEMP_DATABASE} DatabaseOnRemote.kdbx +exit +--- +{TEMP_DATABASE} is used as placeholder to store the database in a temporary location +The command has to exit. In case of `sftp` as last command `exit` has to be sent + + np.: +put {TEMP_DATABASE} ZdalnaBazaDanych.kdbx +exit +--- +{TEMP_DATABASE} służy jako symbol zastępczy do przechowywania bazy danych w tymczasowej lokalizacji +Polecenie musi się zakończyć. W przypadku `sftp` jako ostatniego polecenia należy wysłać `exit` + + + + Timeout: + Przekroczenie limitu czasu: + + + seconds + sekundy + + DatabaseTabWidget @@ -2335,6 +2602,11 @@ Jest to z pewnością błąd, zgłoś go programistom. Database tab name modifier %1 [Zablokowana] + + %1 [Temporary] + Database tab name modifier + %1 [Tymczasowa] + DatabaseWidget @@ -2458,26 +2730,6 @@ Zapisać zmiany? File has changed Plik się zmienił - - The database file has changed. Do you want to load the changes? - Plik bazy danych uległ zmianie. Czy chcesz załadować zmiany? - - - Merge Request - Żądanie scalenia - - - The database file has changed and you have unsaved changes. -Do you want to merge your changes? - Plik bazy danych został zmieniony, a masz niezapisane zmiany. -Czy chcesz scalić Twoje zmiany? - - - Could not open the new database file while attempting to autoreload. -Error: %1 - Nie można otworzyć nowego pliku bazy danych podczas próby automatycznego przeładowania. -Błąd: %1 - Disable safe saves? Wyłączyć bezpieczne zapisywanie? @@ -2529,6 +2781,86 @@ Wyłączyć bezpieczne zapisywanie i spróbować ponownie? Database tab name modifier %1 [Nowa baza danych] + + Remote Sync did not contain any download or upload commands. + Synchronizacja zdalna nie zawierała żadnych poleceń pobierania ani wysyłania. + + + Remote sync '%1' completed successfully! + Zdalna synchronizacja '%1' zakończona pomyślnie! + + + Remote sync '%1' failed: %2 + Zdalna synchronizacja '%1' nie powiodła się: %2 + + + Error while saving database %1: %2 + Błąd podczas zapisywania bazy danych %1: %2 + + + Downloading... + Pobieranie... + + + Uploading... + Wysyłanie... + + + Syncing... + Synchronizowanie... + + + Remove passkey from entry + Usuń klucz dostępu z wpisu + + + Do you want to remove the passkey from this entry? + Czy chcesz usunąć klucz dostępu z tego wpisu? + + + The database file "%1" was modified externally + Plik bazy danych "%1" został zmodyfikowany zewnętrznie + + + Do you want to load the changes? + Czy chcesz załadować zmiany? + + + Reload database + Załaduj ponownie bazę danych + + + Reloading database… + Ponowne ładowanie bazy danych… + + + Reload canceled + Anulowano ponowne ładowanie + + + Reload successful + Ponowne ładowanie powiodło się + + + Reload pending user action… + Załaduj ponownie oczekującą czynność użytkownika… + + + The database file "%1" was modified externally.<br>How would you like to proceed?<br><br>Merge all changes<br>Ignore the changes on disk until save<br>Discard unsaved changes + Plik bazy danych "%1" został zmodyfikowany zewnętrznie.<br>Jak chcesz kontynuować?<br><br>Scal wszystkie zmiany<br>Ignoruj ​​zmiany na dysku do momentu zapisania<br>Odrzuć niezapisane zmiany + + + The database file "%1" was modified externally.<br>How would you like to proceed?<br><br>Merge all changes then save<br>Overwrite the changes on disk<br>Discard unsaved changes + Plik bazy danych "%1" został zmodyfikowany zewnętrznie.<br>Jak chcesz kontynuować?<br><br>Scal wszystkie zmiany, a następnie zapisz<br>Nadpisz zmiany na dysku<br>Odrzuć niezapisane zmiany + + + Database file overwritten. + Plik bazy danych został nadpisany. + + + Database file on disk cannot be unlocked with current credentials.<br>Enter new credentials and/or present hardware key to continue. + Pliku bazy danych na dysku nie można odblokować przy użyciu bieżących danych uwierzytelniających.<br>Aby kontynuować, wprowadź nowe dane uwierzytelniające i/lub obecny klucz sprzętowy. + EditEntryWidget @@ -2580,10 +2912,6 @@ Wyłączyć bezpieczne zapisywanie i spróbować ponownie? n/a nie dotyczy - - (encrypted) - (zaszyfrowane) - Select private key Wybierz klucz prywatny @@ -2686,6 +3014,10 @@ Czy chcesz go poprawić? %n year(s) %n rok%n lata%n lat%n lat + + Failed to decrypt SSH key, ensure password is correct. + Nie udało się odszyfrować klucza SSH. Upewnij się, że hasło jest poprawne. + EditEntryWidgetAdvanced @@ -2857,18 +3189,10 @@ Czy chcesz go poprawić? Skip Auto-Submit for this entry Pomiń autoprzesyłanie dla tego wpisu - - Only send this setting to the browser for HTTP Auth dialogs. If enabled, normal login forms will not show this entry for selection. - Wyślij to ustawienie do przeglądarki tylko w przypadku okien dialogowych uwierzytelniania HTTP. Jeśli ta opcja jest włączona, zwykłe formularze logowania nie będą wyświetlać tego wpisu do wyboru. - Use this entry only with HTTP Basic Auth Użyj tego wpisu tylko w przypadku podstawowego uwierzytelniania HTTP - - Do not send this setting to the browser for HTTP Auth dialogs. If enabled, HTTP Auth dialogs will not show this entry for selection. - Nie wysyłaj tego ustawienia do przeglądarki w przypadku okien dialogowych uwierzytelniania HTTP. Jeśli jest włączone, okna dialogowe uwierzytelniania HTTP nie będą pokazywać tego wpisu do wyboru. - Do not use this entry with HTTP Basic Auth Nie używaj tego wpisu z podstawowym uwierzytelnianiem HTTP @@ -2893,6 +3217,14 @@ Czy chcesz go poprawić? Additional URLs Dodatkowe adresy URL + + Only send this entry to the browser for HTTP Auth dialogs. If enabled, normal login forms will not show this entry for selection. + Wysyłaj ten wpis do przeglądarki tylko w przypadku okien dialogowych uwierzytelniania HTTP. Jeśli ta opcja jest włączona, zwykłe formularze logowania nie będą wyświetlać tego wpisu do wyboru. + + + Do not send this entry to the browser for HTTP Auth dialogs. If enabled, HTTP Auth dialogs will not show this entry for selection. + Nie wysyłaj tego wpisu do przeglądarki w przypadku okien dialogowych uwierzytelniania HTTP. Jeśli ta opcja jest włączona, okna dialogowe uwierzytelniania HTTP nie będą pokazywać tego wpisu do wyboru. + EditEntryWidgetHistory @@ -3115,6 +3447,10 @@ Czy chcesz go poprawić? seconds sekundy + + Clear agent + Wyczyść agenta + EditGroupWidget @@ -3557,6 +3893,24 @@ Może to spowodować nieprawidłowe działanie wtyczek. %1 - Clone %1 - klon + + Passkey + Klucz dostępu + + + Invalid conversion type: %1 + Nieprawidłowy typ konwersji: %1 + + + Invalid conversion syntax: %1 + Nieprawidłowa składnia konwersji: %1 + + + Invalid regular expression syntax %1 +%2 + Nieprawidłowa składnia wyrażenia regularnego %1 +%2 + EntryAttachments @@ -3565,6 +3919,21 @@ Może to spowodować nieprawidłowe działanie wtyczek. Nie można otworzyć pliku "%1" + + EntryAttachmentsDialog + + Form + Formularz + + + File name + Nazwa pliku + + + File contents... + Zawartość pliku... + + EntryAttachmentsModel @@ -3602,14 +3971,6 @@ Może to spowodować nieprawidłowe działanie wtyczek. Remove Usuń - - Rename selected attachment - Zmień nazwę wybranego załącznika - - - Rename - Zmień nazwę - Open selected attachment Otwórz wybrany załącznik @@ -3727,6 +4088,18 @@ Would you like to overwrite the existing attachment? Załącznik "%1" już istnieje. Czy chcesz zastąpić istniejący załącznik? + + New + Nowy + + + Preview + Podgląd + + + Failed to preview an attachment: Attachment not found + Nie udało się wyświetlić podglądu załącznika: nie został on znaleziony + EntryAttributesModel @@ -3925,6 +4298,10 @@ Czy chcesz zastąpić istniejący załącznik? Background Color Kolor tła + + Group Path + Ścieżka grupy + EntryPreviewWidget @@ -4320,6 +4697,14 @@ Możesz włączyć usługę ikon witryn DuckDuckGo w sekcji bezpieczeństwa usta Url Adres URL + + Could not load key file. + Nie można załadować pliku klucza. + + + Could not open remote database. Password or key file may be incorrect. + Nie można otworzyć zdalnej bazy danych. Hasło lub plik klucza mogą być nieprawidłowe. + ImportWizardPageSelect @@ -4423,6 +4808,50 @@ Możesz włączyć usługę ikon witryn DuckDuckGo w sekcji bezpieczeństwa usta KeePass1 Database Baza danych KeePass 1 + + Proton Pass (.json) + Proton Pass (.json) + + + Proton Pass JSON Export + Eksport JSON Proton Pass + + + Temporary Database + Tymczasowa baza danych + + + Command: + Polecenie: + + + e.g.: "sftp user@hostname" or "scp user@hostname:DatabaseOnRemote.kdbx {TEMP_DATABASE}" + np.: "sftp użytkownik@nazwahosta" lub "scp użytkownik@nazwahosta:ZdalnaBazaDanych.kdbx {TEMP_DATABASE}" + + + Input: + Wejście: + + + e.g.: +get DatabaseOnRemote.kdbx {TEMP_DATABASE} +exit +--- +{TEMP_DATABASE} is used as placeholder to store the database in a temporary location +The command has to exit. In case of `sftp` as last commend `exit` has to be sent + + np.: +get ZdalnaBazaDanych.kdbx {TEMP_DATABASE} +exit +--- +{TEMP_DATABASE} służy jako symbol zastępczy do przechowywania bazy danych w tymczasowej lokalizacji +Polecenie musi się zakończyć. W przypadku `sftp` jako ostatniego polecenia należy wysłać `exit` + + + + Remote Database (.kdbx) + Zdalna baza danych (.kdbx) + KMessageWidget @@ -5563,12 +5992,6 @@ Ta wersja nie jest przeznaczona do użytku produkcyjnego. Expect some bugs and minor issues, this version is meant for testing purposes. UWAGA: Używasz wstępnej wersji KeePassXC. Spodziewaj się pewnych błędów i drobnych problemów, ta wersja jest przeznaczona do celów testowych. - - - WARNING: Your Qt version may cause KeePassXC to crash with an On-Screen Keyboard. -We recommend you use the AppImage available on our downloads page. - OSTRZEŻENIE: Twoja wersja Qt może powodować awarie KeePassXC z klawiaturą ekranową. -Zalecamy korzystanie z AppImage dostępnego na naszej stronie pobierania. No Tags @@ -5642,6 +6065,10 @@ Zalecamy korzystanie z AppImage dostępnego na naszej stronie pobierania.Import Passkey Importuj klucz dostępu + + Remote S&ync… + Zdalna s&ynchronizacja… + Quit Application Zakończ aplikację @@ -5746,6 +6173,10 @@ Zalecamy korzystanie z AppImage dostępnego na naszej stronie pobierania.Show Password Generator Pokaż generator haseł + + Remove Passkey From Entry + Usuń klucz dostępu z wpisu + Perform Auto-Type: {USERNAME} Wykonaj autowpisywanie: {USERNAME} @@ -5890,6 +6321,34 @@ Zalecamy korzystanie z AppImage dostępnego na naszej stronie pobierania.Toggle Allow Screen Capture Przełącz zezwalanie na przechwytywanie ekranu + + Show Group Panel + Pokaż panel grup + + + Toggle Show Group Panel + Przełącz pokazywanie panelu grup + + + Setup Remote Sync… + Skonfiguruj zdalną synchronizację… + + + Password Generator + Generator haseł + + + E&xpire Entry… + Wy&gaś wpis… + + + Clear SSH Agent + Wyczyść agenta SSH + + + Clear all identities in ssh-agent + Wyczyść wszystkie tożsamości w ssh-agent + ManageDatabase @@ -6040,6 +6499,25 @@ Zalecamy korzystanie z AppImage dostępnego na naszej stronie pobierania.Uzupełnij wyświetlaną nazwę i opcjonalny opis nowej bazy danych: + + NewEntryAttachmentsDialog + + Attachment name cannot be empty + Nazwa załącznika nie może być pusta + + + Attachment with the same name already exists + Załącznik o tej samej nazwie już istnieje + + + Save attachment + Zapisz załącznik + + + New entry attachment + Nowy załącznik wpisu + + NixUtils @@ -6227,6 +6705,10 @@ Zalecamy korzystanie z AppImage dostępnego na naszej stronie pobierania.Unexpected EOF when writing private key Nieoczekiwany koniec pliku (EOF) podczas zapisu klucza prywatnego + + (encrypted) + (zaszyfrowane) + OpenSSHKeyGenDialog @@ -6275,7 +6757,7 @@ Zalecamy korzystanie z AppImage dostępnego na naszej stronie pobierania. Export the following passkey entries. - + Eksportuj następujące wpisy klucza dostępu. @@ -6289,7 +6771,8 @@ Zalecamy korzystanie z AppImage dostępnego na naszej stronie pobierania. Plik "%1.passkey" już istnieje. -Czy chcesz go zastąpić? +Czy chcesz go zastąpić? + Cannot open file @@ -6348,15 +6831,15 @@ Czy chcesz go zastąpić? Import the following passkey: - + Importuj następujący klucz dostępu: Import the following passkey to this entry: - + Importuj następujący klucz dostępu do tego wpisu: Default passkeys group (Imported Passkeys) - + Domyślna grupa kluczy dostępu (importowane klucze dostępu) @@ -6379,25 +6862,27 @@ Czy chcesz go zastąpić? Open passkey file - + Otwórz plik klucza dostępu Cannot import passkey - + Nie można zaimportować klucza dostępu Cannot import passkey file "%1". Data is missing. - + Nie można zaimportować pliku klucza dostępu "%1". Brak danych. Cannot import passkey file "%1". The following data is missing: %2 - + Nie można zaimportować pliku klucza dostępu "%1". +Brakuje następujących danych: +%2 Cannot import passkey file "%1". Private key is missing or malformed. - + Nie można zaimportować pliku klucza dostępu "%1". Brak klucza prywatnego lub jest on źle sformatowany. @@ -6578,10 +7063,6 @@ The following data is missing: Also choose from: Wybierz także: - - Excluded characters: "0", "1", "l", "I", "O", "|", "﹒" - Wykluczone znaki: "0", "1", "l", "I", "O", "|", "﹒" - Exclude look-alike characters Wyklucz podobnie wyglądające znaki @@ -6606,10 +7087,6 @@ The following data is missing: Word Count: Liczba słów: - - Character Count: - Liczba znaków: - Word Case: Rozmiar słowa: @@ -6622,10 +7099,6 @@ The following data is missing: Add custom wordlist Dodaj niestandardową listę słów - - character - znak - Close Zamknij @@ -6732,6 +7205,22 @@ Czy chcesz ją zastąpić? Special Characters Znaki specjalne + + passwordLength + Długość hasła + + + Characters: %1 + Znaki: %1 + + + MIXED case + MIESZANE litery + + + Excluded characters: "0", "1", "l", "I", "O", "|", "﹒", "B", "8", "G", "6" + Wykluczone znaki: "0", "1", "l", "I", "O", "|", "﹒", "B", "8", "G", "6" + PasswordWidget @@ -6799,6 +7288,21 @@ Czy chcesz ją zastąpić? Naciskaj &Tab między znakami + + PreviewEntryAttachmentsDialog + + Preview entry attachment + Podgląd załącznika wpisu + + + No preview available + Brak podglądu + + + Image format not supported + Format obrazu nie jest obsługiwany + + QMessageBox @@ -7168,7 +7672,7 @@ Czy chcesz ją zastąpić? ERROR: Please specify one of --attribute or --totp, not both. - BŁĄD: Proszę określić jeden z --atrybut lub --totp, a nie oba. + BŁĄD: Określ jeden z --attribute lub --totp, a nie oba. Entry with path %1 has no TOTP set up. @@ -7477,10 +7981,6 @@ Czy chcesz ją zastąpić? Invalid word count %1 Nieprawidłowa liczba wyrazów %1 - - The word list is too small (< 1000 items) - Lista wyrazów jest za mała (< 1000 elementów) - Title for the entry. Tytuł dla wpisu. @@ -7625,10 +8125,6 @@ Czy chcesz ją zastąpić? Exit interactive mode. Wyjdź z trybu interaktywnego. - - Format to use when exporting. Available choices are 'xml' or 'csv'. Defaults to 'xml'. - Formatowanie do użycia podczas eksportowania. Dostępne opcje to 'xml' lub 'csv'. Domyślnie wartość 'xml'. - Exports the content of a database to standard output in the specified format. Eksportuje zawartość bazy danych do standardowego wyjścia w określonym formacie. @@ -7911,7 +8407,7 @@ Dostępne polecenia: Names of the attributes to show. This option can be specified more than once, with each attribute shown one-per-line in the given order. If no attributes are specified, a summary of the default attributes is given. - Nazwy atrybutów do wyświetlenia. Tą opcję można zastosować więcej niż jeden raz, podając każdy atrybut w osobnym wierszu w określonej kolejności. Jeśli atrybuty nie są określone, wyświetla się podsumowanie domyślnych atrybutów. + Nazwy atrybutów do wyświetlenia. Tę opcję można zastosować więcej niż jeden raz, podając każdy atrybut w osobnym wierszu i w określonej kolejności. Jeśli atrybuty nie są określone, wyświetla się podsumowanie domyślnych atrybutów. attribute @@ -8217,18 +8713,6 @@ Jądro: %3 %4 file empty plik pusty - - malformed string - nieprawidłowy ciąg - - - missing closing quote - brak cytatu zamknięcia - - - %1: (row, col) %2,%3 - %1: (rząd, kolumna) %2,%3 - AES 256-bit AES 256-bitowy @@ -8674,12 +9158,88 @@ Ta opcja jest przestarzała, zamiast jej użyj --set-key-file. Skróty - Unsupported KDF type, cannot decrypt json file - Nieobsługiwany typ KDF, nie można odszyfrować pliku JSON + Unknown passkeys error + Nieznany błąd klucza dostępu - Unknown passkeys error - + Invalid KDF iterations, cannot decrypt json file + Nieprawidłowe iteracje KDF, nie można odszyfrować pliku JSON + + + Unsupported format, ensure your Bitwarden export is password-protected + Nieobsługiwany format. Upewnij się, że eksport Bitwarden jest chroniony hasłem + + + Only PBKDF and Argon2 are supported, cannot decrypt json file + Obsługiwane są tylko PBKDF i Argon2, nie można odszyfrować pliku JSON + + + Reset Shortcuts + Zresetuj skróty + + + Double click an action to change its shortcut + Kliknij dwukrotnie czynność, aby zmienić jej skrót + + + Filter... + Filtr... + + + Shortcut Conflict + Konflikt skrótów + + + Shortcut %1 conflicts with '%2'. Overwrite shortcut? + Skrót %1 powoduje konflikt z '%2'. Nadpisać skrót? + + + Cannot generate valid passphrases because the wordlist is too short + Nie można wygenerować prawidłowych haseł, ponieważ lista słów jest zbyt krótka + + + Encrypted files are not supported. + Pliki zaszyfrowane nie są obsługiwane. + + + Proton Pass Import + Import Proton Pass + + + Delete plugin data? + Usunąć dane wtyczki? + + + Delete plugin data from Entry(s)? + Usunąć dane wtyczki z wpisu?Usunąć dane wtyczki z wpisów?Usunąć dane wtyczki z wpisów?Usunąć dane wtyczki z wpisów? + + + Passkey + Klucz dostępu + + + Format to use when exporting. Available choices are 'xml', 'csv' or 'html'. Defaults to 'xml'. + Format do użycia podczas eksportowania. Dostępne opcje to 'xml', 'csv' lub 'html'. Domyślnie 'xml'. + + + start minimized to the system tray + uruchom zminimalizowany do zasobnika systemowego + + + malformed string, possible unescaped delimiter + zniekształcony ciąg, prawdopodobnie ogranicznik bez ucieczki + + + missing closing delimiter + brak ogranicznika zamykającego + + + %1, row: %2, column: %3 + %1, wiersz: %2, kolumna: %3 + + + Tags + Tagi @@ -8716,6 +9276,37 @@ Ta opcja jest przestarzała, zamiast jej użyj --set-key-file. Błąd wewnętrzny zlib: + + RemoteHandler + + Command `%1` did not finish in time. Process was killed. + Polecenie `%1` nie zostało zakończone na czas. Proces został usunięty. + + + Failed to upload merged database. Command `%1` did not finish in time. Process was killed. + Nie udało się wysłać scalonej bazy danych. Polecenie `%1` nie zostało zakończone na czas. Proces został usunięty. + + + Invalid download parameters provided. + Podano nieprawidłowe parametry pobierania. + + + Command `%1` failed to download database. + Poleceniu `%1` nie udało się pobrać bazy danych. + + + Invalid database pointer or upload parameters provided. + Podano nieprawidłowy wskaźnik bazy danych lub parametry wysyłania. + + + Command `%1` exited with status code: %2 + Polecenie `%1` zostało zakończone z kodem stanu: %2 + + + Failed to upload merged database. Command `%1` exited with status code: %2 + Nie udało się wysłać scalonej bazy danych. Polecenie `%1` zostało zakończone z kodem stanu: %2 + + ReportsWidgetBrowserStatistics @@ -8782,6 +9373,10 @@ Ta opcja jest przestarzała, zamiast jej użyj --set-key-file. Exclude from reports Wyklucz z raportów + + Expire Entry(s)… + Wygaś wpis…Wygaś wpisy…Wygaś wpisy…Wygaś wpisy… + Only show entries that have a URL Pokaż tylko wpisy, które mają adres URL @@ -8798,36 +9393,33 @@ Ta opcja jest przestarzała, zamiast jej użyj --set-key-file. (Expired) (Wygasłe) + + Delete plugin data from Entry(s)… + Usuń dane wtyczki z wpisu…Usuń dane wtyczki z wpisów…Usuń dane wtyczki z wpisów…Usuń dane wtyczki z wpisów… + ReportsWidgetHealthcheck - Hover over reason to show additional details. Double-click entries to edit. - Umieść wskaźnik myszy nad powodem, aby wyświetlić dodatkowe szczegóły. Kliknij dwukrotnie wpisy, aby edytować. + Show expired entries + Pokaż wygasłe wpisy - Bad - Password quality - Zła + (Expired) + (Wygasłe) + + + Hover over reason to show additional details. Double-click entries to edit. + Umieść wskaźnik myszy nad powodem, aby wyświetlić dodatkowe szczegóły. Kliknij dwukrotnie wpisy, aby edytować. Bad — password must be changed Złe — hasło musi zostać zmienione - - Poor - Password quality - Uboga - Poor — password should be changed Ubogie — hasło powinno zostać zmienione - - Weak - Password quality - Słaba - Weak — consider changing the password Słabe — rozważ zmianę hasła @@ -8876,18 +9468,14 @@ Ta opcja jest przestarzała, zamiast jej użyj --set-key-file. Exclude from reports Wyklucz z raportów - - Show expired entries - Pokaż wygasłe wpisy + + Expire Entry(s)… + Wygaś wpis…Wygaś wpisy…Wygaś wpisy…Wygaś wpisy… Show entries that have been excluded from reports Pokaż wpisy, które zostały wykluczone z raportów - - (Expired) - (Wygasłe) - ReportsWidgetHibp @@ -8983,6 +9571,10 @@ Ta opcja jest przestarzała, zamiast jej użyj --set-key-file. Exclude from reports Wyklucz z raportów + + Expire Entry(s)… + Wygaś wpis…Wygaś wpisy…Wygaś wpisy…Wygaś wpisy… + ReportsWidgetPasskeys @@ -9044,11 +9636,11 @@ Ta opcja jest przestarzała, zamiast jej użyj --set-key-file. Please wait, list of entries with passkeys is being updated… - + Proszę czekać, lista wpisów z kluczami dostępu jest aktualizowana… No entries with passkeys. - + Brak wpisów z kluczami dostępu. @@ -9224,6 +9816,14 @@ Ta opcja jest przestarzała, zamiast jej użyj --set-key-file. No agent running, cannot list identities. Żaden agent uruchomiony, nie może wyświetlić listy tożsamości. + + Failed to remove all SSH identities from agent. + Nie udało się usunąć wszystkich tożsamości SSH agenta. + + + All SSH identities removed from agent. + Wszystkie tożsamości SSH zostały usunięte z agenta. + SearchHelpWidget @@ -9402,7 +10002,7 @@ Ta opcja jest przestarzała, zamiast jej użyj --set-key-file. <html><head/><body><p>This improves compatibility with certain applications which search for password without unlocking the database first.</p><p>But enabling this may also crash the client if the database can not be unlocked within a certain timeout. (Usually 25s, but may be a different value set in applications.) </p></body></html> - <html><head/><body><p>Poprawia to kompatybilność z niektórymi aplikacjami, które szukają hasła bez uprzedniego odblokowania bazy danych.</p><p>Ale włączenie tego może również spowodować awarię klienta, jeśli bazy danych nie można odblokować w określonym czasie (zwykle 25 s, ale w aplikacjach może to być inna wartość). </p></body></html> + <html><head/><body><p>Poprawia to kompatybilność z niektórymi aplikacjami, które szukają hasła bez uprzedniego odblokowania bazy danych.</p><p>Ale włączenie tego może również spowodować awarię klienta, jeśli bazy danych nie można odblokować w określonym czasie (zwykle 25 s, ale w aplikacjach może to być inna wartość). </p></body></html> @@ -9509,29 +10109,6 @@ Ta opcja jest przestarzała, zamiast jej użyj --set-key-file. Eksportuj do %1 - - ShortcutSettingsWidget - - Double click an action to change its shortcut - Kliknij dwukrotnie czynność, aby zmienić jej skrót - - - Shortcut Conflict - Konflikt skrótów - - - Filter... - Filtr... - - - Shortcut %1 conflicts with '%2'. Overwrite shortcut? - Skrót %1 powoduje konflikt z '%2'. Nadpisać skrót? - - - Reset Shortcuts - Zresetuj skróty - - TagModel @@ -9820,14 +10397,18 @@ Przykład: JBSWY3DPEHPK3PXP No hardware keys detected Nie wykryto kluczy sprzętowych - - <p>If you own a <a href="https://www.yubico.com/">YubiKey</a> or <a href="https://onlykey.io">OnlyKey</a>, you can use it for additional security.</p><p>The key requires one of its slots to be programmed as <a href="https://docs.yubico.com/yesdk/users-manual/application-otp/challenge-response.html">HMAC-SHA1 Challenge-Response</a>.</p> - <p>Jeśli masz <a href="https://www.yubico.com/">YubiKey</a> lub <a href="https://onlykey.io">OnlyKey</a>, możesz go użyć do zwiększenia bezpieczeństwa.</p><p>Wymaga on zaprogramowania jednego z jego gniazd jako <a href="https://docs.yubico.com/yesdk/users-manual/application-otp/challenge-response.html">wyzwanie-odpowiedź HMAC-SHA1</a>.</p> - Refresh hardware keys Odśwież klucze sprzętowe + + <p>If you own a <a href="https://www.yubico.com/">YubiKey</a> or <a href="https://onlykey.io">OnlyKey</a>, you can use it for additional security.</p><p>The key requires one of its slots to be programmed with <a href="https://keepassxc.org/docs/#faq-yubikey-howto">Challenge-Response</a>.</p> + <p>Jeśli jesteś właścicielem <a href="https://www.yubico.com/">YubiKey</a> lub <a href="https://onlykey.io">OnlyKey</a>, możesz użyć takiego klucza do zwiększenia bezpieczeństwa.</p><p>Wymaga on zaprogramowania jednego z jego gniazd w trybie <a href="https://keepassxc.org/docs/#faq-yubikey-howto">wyzwanie-odpowiedź</a>.</p> + + + Hardware keys found, but no slots are configured + Znaleziono klucze sprzętowe, ale nie skonfigurowano żadnych gniazd + YubiKeyInterfacePCSC diff --git a/share/translations/keepassxc_pt_BR.ts b/share/translations/keepassxc_pt_BR.ts index 0d845aa77..a81297047 100644 --- a/share/translations/keepassxc_pt_BR.ts +++ b/share/translations/keepassxc_pt_BR.ts @@ -217,18 +217,50 @@ You must restart the application to set the new language. Would you like to restart now? Você precisa reiniciar o aplicativo para aplicar o novo idioma. Você gostaria de reiniciar agora? - - Reset Settings? - Restaurar as configurações? - - - Are you sure you want to reset all general and security settings to default? - Tem certeza que deseja restaurar todas as configurações gerais e as configurações de segurança para o padrão? - Select backup storage directory Selecione o diretório onde o backup será armazenado + + Confirm Reset + Confirmar Redefinição + + + Are you sure you want to reset all settings to default? + Tem certeza de que deseja redefinir todas as configurações para o padrão? + + + Import KeePassXC Settings + Importar Configurações do KeePassXC + + + Failed to import settings from %1, not a valid settings file. + Falha ao importar configurações de %1; arquivo de configurações inválido. + + + Export KeePassXC Settings + Exportar Configurações do KeePassXC + + + Small + Pequeno + + + Normal + Normal + + + Medium + Médio + + + Large + Grande + + + Custom + Personalizado + ApplicationSettingsWidgetGeneral @@ -262,7 +294,7 @@ recent files - arquivos recentes + arquivos recentes Load previously open databases on startup @@ -280,25 +312,6 @@ Include beta releases when checking for updates Incluir versões betas durante a verificação de atualizações - - On database unlock, show entries that - Ao desbloquear o banco de dados, mostrar entradas que - - - have expired - On database unlock, show entries that... - Caducou - - - days - On database unlock, show entries that will expire within %1 days - dias - - - will expire within - On database unlock, show entries that... - irá expirar dentro de - File Management Gerenciador de arquivo @@ -323,22 +336,10 @@ Backup database file before saving Fazer cópia de segurança do banco de dados antes de salvar - - Backup destination - Destino do backup - - - Specifies the database backup file location. Occurrences of "{DB_FILENAME}" are replaced with the filename of the saved database without extension. {TIME:<format>} is replaced with the backup time, see https://doc.qt.io/qt-5/qdatetime.html#toString. <format> defaults to format string "dd_MM_yyyy_hh-mm-ss". - Especifica a localização para o backup do banco de dados. As ocorrências de "{DB_FILENAME}" serão substituídas pelo nome do arquivo do banco de dados salvo mas sem extensão. {TIME:<format>} será substituído pelo horário do backup. Consulte https://doc.qt.io/qt-5/qdatetime.html#toString. <format> Os valores padrão a utilizar serão "dd_MM_yyyy_hh-mm-ss". - {DB_FILENAME}.old.kdbx {DB_FILENAME}.antigo.kdbx - - Choose... - Escolher... - Use alternative saving method (may solve problems with Dropbox, Google Drive, GVFS, etc.) Usar método alternativo de salvamento (pode resolver problemas com Dropbox, Google Drive, GVFS, etc) @@ -505,6 +506,71 @@ Remember last typed entry for: Lembrar última entrada digitada para: + + On database unlock, show entries that will expire within + No desbloqueio do banco de dados, mostre as entradas que expirarão dentro + + + On database unlock, show entries that will expire within + No desbloqueio do banco de dados, mostre as entradas que expirarão dentro + + + days + number of days warning for password expiration + dias + + + Destination format: + Formato de destino: + + + <html><head/><body><p><span style=" font-weight:600;">{DB_FILENAME}</span> is replaced with the filename of the saved database without extension</p><p><span style=" font-weight:600;">{TIME:&lt;format&gt;}</span> is replaced with the specified time format (default: dd_MM_yyyy_hh-mm-ss)</p><p>See the User Guide for more details</p></body></html> + <html><head/><body><p><span style=" font-weight:600;">{DB_FILENAME}</span> é substituído pelo nome do arquivo do banco de dados salvo sem extensão</p><p><span style=" font-weight:600;">{TIME:&lt;format&gt;}</span> é substituído pelo formato de hora especificado (default: dd_MM_yyyy_hh-mm-ss)</p><p>Consulte o Guia do Usuário para obter mais detalhes</p></body></html> + + + Choose folder... + Escolher a pasta: + + + Show confirmation before moving entries to recycle bin + Mostrar confirmação antes de mover entradas para a lixeira + + + Copy data on double clicking field in entry view + Copie os dados no campo de clique duplo na entrada exibida + + + Show toolbar + Mostrar barra de ferramentas + + + Show the menu bar by pressing the Alt key + Mostrar a barra de menu pressionando a tecla Alt + + + Show menubar + Exibir barra de menu + + + Import settings… + Importar configurações... + + + Export settings… + Exportar configurações... + + + Open browser on double clicking URL field in entry view + Abra o navegador clicando duas vezes no campo URL na entrada exibida + + + Font size: + Tamanho da fonte: + + + Font size selection + Seleção do tamanho da fonte + ApplicationSettingsWidgetSecurity @@ -570,18 +636,6 @@ Hide passwords in the entry preview panel Ocultar senhas no painel da prévia de entrada - - Hide entry notes by default - Esconder notas de entrada por padrão - - - Move entries to recycle bin without confirmation - Mover entradas para a lixeira sem confirmação - - - Enable double click to copy the username/password entry columns - Ativar duplo clique para copiar a entrada nome de utilizador/palavra-passe - Privacy Privacidade @@ -594,6 +648,18 @@ Hide TOTP in the entry preview panel Ocultar TOTP no painel de visualização da entrada + + Lock databases when switching user + Bloquear bancos de dados ao trocar de usuário + + + Lock Options + Opções de Bloqueio + + + Hide notes in the entry preview panel + Ocultar notas no painel de visualização da entrada + AutoType @@ -641,20 +707,6 @@ Entry does not have attribute for PICKCHARS: %1 A entrada não tem o atributo para PICKCHARS: %1 - - Invalid conversion type: %1 - Tipo de conversão inválido: %1 - - - Invalid conversion syntax: %1 - Sintaxe de conversão inválida: %1 - - - Invalid regular expression syntax %1 -%2 - Sintaxe de expressão regular inválida %1 -%2 - Invalid placeholder: %1 Marcador de posição inválido: %1 @@ -714,7 +766,7 @@ Trying to send invalid keyboard symbol. - + Tentando enviar um símbolo inválido de teclado. @@ -886,24 +938,27 @@ Por favor, selecione o banco de dados correto para salvar as credenciais. Add to existing entry - + Adicionar à entrada já existente Existing passkey found. Do you want to register a new passkey for: - + Uma chave de acesso já existente foi encontrada. +Deseja registrar uma nova chave de acesso para: + + Select the existing passkey and press Update to replace it. - + Selecione a chave de acesso existente e pressione atualizar para substituí-la. Authenticate passkey credentials for: - + Autenticar credenciais de chave de acesso para: Do you want to register a passkey for: - + Deseja registrar uma chave de acesso para: @@ -988,16 +1043,17 @@ Você quer excluir a entrada? Register a new passkey to this entry: - + Registrar uma nova chave de acesso para esta entrada: KeePassXC - Update passkey - + KeePassXC - Atualizar a chave de acesso Entry already has a passkey. Do you want to overwrite the passkey in %1 - %2? - + A entrada já tem uma chave de acesso. +Deseja substituir a chave de acesso em %1 - %2? Register @@ -1022,10 +1078,6 @@ Do you want to overwrite the passkey in %1 - %2? General Geral - - Browsers installed as snaps are currently not supported. - Navegadores instalados como snaps atualmente não são suportados. - Enable integration for these browsers: Habilitar integração para estes navegadores: @@ -1197,18 +1249,6 @@ Do you want to overwrite the passkey in %1 - %2? Custom extension ID ID de extensão personalizado: - - Due to Snap sandboxing, you must run a script to enable browser integration.<br />You can obtain this script from %1 - Devido ao sandbox do Snap, você deve executar um script para ativar a integração do navegador.<br />Você pode obter este script de %1 - - - KeePassXC-Browser is needed for the browser integration to work. <br />Download it for %1 and %2 and %3. %4 - O KeePassXC-Browser é necessário para que a integração com navegador funcione. Faça o download para %1, %2 e %3. %4 - - - Please see special instructions for browser extension use below - Por favor, veja as instruções especiais para o uso da extensão do navegador abaixo - Executable Files Arquivos Executáveis @@ -1251,11 +1291,19 @@ Do you want to overwrite the passkey in %1 - %2? Allows using insecure http://localhost with passkeys for testing purposes. - + Permite o uso inseguro de http://localhost com chaves de acesso para fins de teste. Allow using localhost with passkeys - + Permite o uso do localhost com as chaves de acesso + + + KeePassXC-Browser is needed for the browser integration to work. <br />Download it for %1 and %2 and %3. + KeePassXC-Browser é necessário para que a integração do navegador funcione. <br />Baixe-o para %1 e %2 e %3. + + + Browsers installed using Snap or Flatpak are not supported with exception to Firefox installed using Snap. + Navegadores instalados usando Snap ou Flatpak não são suportados, com exceção do Firefox instalado usando Snap. @@ -1399,6 +1447,20 @@ Do you want to overwrite the passkey in %1 - %2? Imported from CSV file: %1 Importado do arquivo CSV: %1 + + No Title Selected + Nenhum Título Selecionado + + + No title column was selected, entries will be hard to tell apart. +Are you sure you want to import? + Nenhuma coluna de título foi selecionada, será difícil distinguir as entradas. +Tem certeza de que deseja importar? + + + Tags + Etiquetas + CsvParserModel @@ -1462,6 +1524,14 @@ Backup do banco de dados alocado em %2 Recycle Bin Lixeira + + Database file read error. + Erro de leitura do arquivo de banco de dados. + + + No file path was provided. + Nenhum caminho de arquivo foi fornecido. + DatabaseOpenDialog @@ -1610,14 +1680,6 @@ Para impedir que esses erros apareçam, você deve ir em "Configurações d <p>In addition to a password, you can use a secret file to enhance the security of your database. This file can be generated in your database's security settings.</p><p>This is <strong>not</strong> your *.kdbx database file!</p> <p>Além de uma senha, você pode usar um arquivo secreto para aumentar a segurança do seu banco de dados. Este arquivo pode ser gerado nas configurações de segurança do seu banco de dados.</p><p>Este <strong>não é</strong> o seu arquivo de banco de dados *.kdbx!</p> - - Click to add a key file. - Clique para adicionar um arquivo-chave. - - - <a href="#" style="text-decoration: underline">I have a key file</a> - Eu tenho um arquivo-chave - Use hardware key [Serial: %1] Usar uma chave de hardware [Serial: %1] @@ -1654,6 +1716,18 @@ Tem certeza de que deseja continuar com este arquivo? Refresh Hardware Keys Atualizar Chaves de Hardware + + Click to add a key file. + Clique para adicionar um arquivo-chave. + + + <a href="#" style="text-decoration: underline">I have a key file</a> + <a href="#" style="text-decoration: underline">Eu tenho um arquivo-chave</a> + + + Hardware keys found, but no slots are configured. + Chaves de hardware encontradas, mas nenhum slot configurado. + DatabaseSettingWidgetMetaData @@ -1688,6 +1762,22 @@ Tem certeza de que deseja continuar com este arquivo? Maintenance Manutenção + + KeeShare + KeeShare + + + Secret Service Integration + Integração com Secret Service + + + Remote Sync + Sincronização Remota + + + Database Settings: %1 + Configurações do Banco de Dados: %1 + DatabaseSettingsWidgetBrowser @@ -1858,14 +1948,14 @@ Tem certeza de que deseja continuar sem uma senha? Weak password Senha fraca - - You must enter a stronger password to protect your database. - Você deve inserir uma senha mais forte para proteger seu banco de dados. - This is a weak password! For better protection of your secrets, you should choose a stronger password. Esta é uma senha fraca! Para melhor proteção dos seus segredos, você deve escolher uma senha mais forte. + + The provided password does not meet the minimum quality requirement. + A senha fornecida não atende aos requisitos mínimos de qualidade. + DatabaseSettingsWidgetEncryption @@ -2003,7 +2093,7 @@ Se você manter este número, seu banco de dados não estará protegido de ataqu thread(s) Threads for parallel execution (KDF settings) - processo(s)processo(s)processo(s) + processo(s) processo(s) processo(s) Encryption Settings: @@ -2167,6 +2257,50 @@ removidos do banco de dados Autosave delay since last change checkbox Atraso de salvamento automático desde a última caixa de seleção + + Public Database Metadata + Metadados do Banco de Dados Público + + + Warning: the following settings are not encrypted. + Aviso: as configurações a seguir não são criptografadas. + + + Display name: + Nome de exibição: + + + Publically visible display name used on the unlock dialog + Nome de exibição publicamente visível usado na caixa de diálogo de desbloqueio + + + Database public display name + Nome de exibição público do banco de dados + + + Display color: + Cor de exibição: + + + Publically visible color used on the unlock dialog + Cor publicamente visível usada na caixa de diálogo de desbloqueio + + + Database public display color chooser + Seletor de cores de exibição pública do banco de dados + + + Clear + Limpar + + + Display icon: + Ícone de exibição: + + + Select Database Icon + Selecionar o Ícone do Banco de Dados + DatabaseSettingsWidgetKeeShare @@ -2262,6 +2396,139 @@ removidos do banco de dados Campo de descrição do banco de dados + + DatabaseSettingsWidgetRemote + + Sync Commands + Comandos de Sincronização + + + Remove + Remover + + + Command Settings + Configurações de Comando + + + Name + Nome + + + Save + Salvar + + + Download + Baixar + + + Command: + Comando: + + + Download command field + Campo do comando baixar + + + e.g.: "sftp user@hostname" or "scp user@hostname:DatabaseOnRemote.kdbx {TEMP_DATABASE}" + por exemplo: 'sftp user@hostname' ou 'scp user@hostname:DatabaseOnRemote.kdbx {TEMP_DATABASE}' + + + Input: + Entrada: + + + Download input field + Campo do comando baixar + + + Upload + Enviar + + + Upload command field + Campo do comando enviar + + + e.g.: "sftp user@hostname" or "scp {TEMP_DATABASE} user@hostname:DatabaseOnRemote.kdbx" + por exemplo: 'sftp user@hostname' ou 'scp {TEMP_DATABASE} user@hostname:DatabaseOnRemote.kdbx' + + + Upload input field + Campo de entrada enviar + + + Name cannot be empty. + O nome não pode ficar vazio. + + + Test + Testar + + + Download command cannot be empty. + O comando de baixar não pode estar vazio. + + + Download failed with error: %1 + Falha ao baixar com erro: %1 + + + Download finished, but file %1 could not be found. + O download foi concluído, mas o arquivo %1 não foi encontrado. + + + Download successful. + Download bem-sucedido. + + + Save Remote Settings + Salvar Configurações Remotas + + + You have unsaved changes. Do you want to save them? + Você tem alterações não salvas. Você quer salvá-los? + + + e.g.: +get DatabaseOnRemote.kdbx {TEMP_DATABASE} +exit +--- +{TEMP_DATABASE} is used as placeholder to store the database in a temporary location +The command has to exit. In case of `sftp` as last command `exit` has to be sent + + por exemplo: +obtenha DatabaseOnRemote.kdbx {TEMP_DATABASE} +sair +--- +{TEMP_DATABASE} é usado como espaço reservado para armazenar o banco de dados em um local temporário +O comando tem que sair. No caso de `sftp` como último comando `exit` deve ser enviado + + + e.g.: +put {TEMP_DATABASE} DatabaseOnRemote.kdbx +exit +--- +{TEMP_DATABASE} is used as placeholder to store the database in a temporary location +The command has to exit. In case of `sftp` as last command `exit` has to be sent + + por exemplo: +coloque {TEMP_DATABASE} DatabaseOnRemote.kdbx +sair +--- +{TEMP_DATABASE} é usado como espaço reservado para armazenar o banco de dados em um local temporário +O comando tem que sair. No caso de `sftp` como último comando `exit` deve ser enviado + + + Timeout: + Esgotamento: + + + seconds + segundos + + DatabaseTabWidget @@ -2335,6 +2602,11 @@ Este é definitivamente um bug, por favor denuncie para os desenvolvedores.Database tab name modifier %1 [Bloqueada] + + %1 [Temporary] + Database tab name modifier + %1 [Temporário] + DatabaseWidget @@ -2458,26 +2730,6 @@ Salvar alterações? File has changed O arquivo foi modificado - - The database file has changed. Do you want to load the changes? - O banco de dados foi alterado. Deseja carregar as alterações? - - - Merge Request - Juntar Pedido - - - The database file has changed and you have unsaved changes. -Do you want to merge your changes? - O arquivo de banco de dados foi alterado e você tem alterações não salvas. -Você deseja combinar suas alterações? - - - Could not open the new database file while attempting to autoreload. -Error: %1 - Não foi possível abrir o novo arquivo de banco de dados ao tentar executar o carregamento automático. -Erro: %1 - Disable safe saves? Desativar armazenamento seguro? @@ -2529,6 +2781,86 @@ Deseja desabilitar salvamento seguro e tentar novamente? Database tab name modifier %1 [Novo banco de dados] + + Remote Sync did not contain any download or upload commands. + A Sincronização Remota não continha nenhum comando de download ou upload. + + + Remote sync '%1' completed successfully! + A sincronização remota '%1' foi concluída com sucesso! + + + Remote sync '%1' failed: %2 + Falha na sincronização remota '%1': %2 + + + Error while saving database %1: %2 + Erro ao salvar o banco de dados %1: %2 + + + Downloading... + Baixando... + + + Uploading... + Enviando... + + + Syncing... + Sincronizando... + + + Remove passkey from entry + Remover a chave de acesso da entrada + + + Do you want to remove the passkey from this entry? + Deseja remover a chave de acesso desta entrada? + + + The database file "%1" was modified externally + O arquivo de banco de dados "%1" foi modificado externamente + + + Do you want to load the changes? + Você quer carregar as alterações? + + + Reload database + Recarregar banco de dados + + + Reloading database… + Recarregando banco de dados... + + + Reload canceled + Recarregar cancelado + + + Reload successful + Recarregar com sucesso + + + Reload pending user action… + Recarregar pendente da ação do usuário... + + + The database file "%1" was modified externally.<br>How would you like to proceed?<br><br>Merge all changes<br>Ignore the changes on disk until save<br>Discard unsaved changes + + + + The database file "%1" was modified externally.<br>How would you like to proceed?<br><br>Merge all changes then save<br>Overwrite the changes on disk<br>Discard unsaved changes + + + + Database file overwritten. + Arquivo de banco de dados substituído. + + + Database file on disk cannot be unlocked with current credentials.<br>Enter new credentials and/or present hardware key to continue. + + EditEntryWidget @@ -2580,10 +2912,6 @@ Deseja desabilitar salvamento seguro e tentar novamente? n/a n/d - - (encrypted) - (criptografado) - Select private key Escolha uma chave privada @@ -2686,6 +3014,10 @@ Gostaria de a corrigir? %n year(s) %n ano%n anos%n anos + + Failed to decrypt SSH key, ensure password is correct. + Houve uma falha ao descriptografar a chave SSH, verifique se a senha está correta. + EditEntryWidgetAdvanced @@ -2857,18 +3189,10 @@ Gostaria de a corrigir? Skip Auto-Submit for this entry Ignorar Auto-Envio para esta entrada - - Only send this setting to the browser for HTTP Auth dialogs. If enabled, normal login forms will not show this entry for selection. - Envia esta configuração apenas ao navegador para caixas de diálogo de Autenticação HTTP. Se ativado, os formulários de login normais não mostrarão esta entrada para seleção. - Use this entry only with HTTP Basic Auth Usar esta entrada somente com Autenticação HTTP Básica - - Do not send this setting to the browser for HTTP Auth dialogs. If enabled, HTTP Auth dialogs will not show this entry for selection. - Não envia esta configuração para o navegador para caixas de diálogo de Autenticação HTTP. Se ativado, as caixas de diálogo de Autenticação HTTP não mostrarão esta entrada para seleção. - Do not use this entry with HTTP Basic Auth Não usar esta entrada com Autenticação HTTP Básica @@ -2887,11 +3211,19 @@ Gostaria de a corrigir? These settings affect the entry's behaviour with the browser extension. - + Estas configurações afetam o comportamento da entrada com a extensão do navegador. Additional URLs - + URLs adicionais + + + Only send this entry to the browser for HTTP Auth dialogs. If enabled, normal login forms will not show this entry for selection. + Envie esta entrada apenas para o navegador para caixas de diálogo de autenticação HTTP. Se ativado, os formulários de login normais não mostrarão esta entrada para seleção. + + + Do not send this entry to the browser for HTTP Auth dialogs. If enabled, HTTP Auth dialogs will not show this entry for selection. + Não envie esta entrada ao navegador para caixas de diálogo de autenticação HTTP. Se ativado, as caixas de diálogo HTTP Auth não mostrarão esta entrada para seleção. @@ -3115,6 +3447,10 @@ Gostaria de a corrigir? seconds segundos + + Clear agent + Limpar agente + EditGroupWidget @@ -3557,6 +3893,24 @@ Isto pode causar mal funcionamento dos plugins afetados. %1 - Clone %1 - Clone + + Passkey + Chave de acesso + + + Invalid conversion type: %1 + Tipo de conversão inválido: %1 + + + Invalid conversion syntax: %1 + Sintaxe de conversão inválida: %1 + + + Invalid regular expression syntax %1 +%2 + Sintaxe de expressão regular inválida %1 +%2 + EntryAttachments @@ -3565,6 +3919,21 @@ Isto pode causar mal funcionamento dos plugins afetados. Não é possível abrir o arquivo %1. + + EntryAttachmentsDialog + + Form + Formulário + + + File name + Nome do arquivo + + + File contents... + Conteúdo do arquivo... + + EntryAttachmentsModel @@ -3602,14 +3971,6 @@ Isto pode causar mal funcionamento dos plugins afetados. Remove Remover - - Rename selected attachment - Renomear anexo selecionado - - - Rename - Renomear - Open selected attachment Abrir anexo selecionado @@ -3726,6 +4087,18 @@ Would you like to overwrite the existing attachment? O anexo "%1" já existe. Deseja fazer a substituição do anexo já existente? + + New + + + + Preview + Visualização + + + Failed to preview an attachment: Attachment not found + Falha ao visualizar um anexo: Anexo não encontrado + EntryAttributesModel @@ -3924,6 +4297,10 @@ Deseja fazer a substituição do anexo já existente? Background Color Cor de fundo + + Group Path + Caminho do Grupo + EntryPreviewWidget @@ -4318,6 +4695,14 @@ Você pode habilitar o serviço de ícones do DuckDuckGo na seção de seguranç Url Url + + Could not load key file. + Não foi possível carregar o arquivo de chave. + + + Could not open remote database. Password or key file may be incorrect. + Não foi possível abrir o banco de dados remoto. A senha ou o arquivo de chave podem estar incorretos. + ImportWizardPageSelect @@ -4421,6 +4806,49 @@ Você pode habilitar o serviço de ícones do DuckDuckGo na seção de seguranç KeePass1 Database Banco de dados do KeePass1 + + Proton Pass (.json) + Proton Pass (.json) + + + Proton Pass JSON Export + Exportar para Proton Pass JSON + + + Temporary Database + Banco de Dados Temporário + + + Command: + Comando: + + + e.g.: "sftp user@hostname" or "scp user@hostname:DatabaseOnRemote.kdbx {TEMP_DATABASE}" + por exemplo: 'sftp user@hostname' ou 'scp user@hostname:DatabaseOnRemote.kdbx {TEMP_DATABASE}' + + + Input: + Entrada: + + + e.g.: +get DatabaseOnRemote.kdbx {TEMP_DATABASE} +exit +--- +{TEMP_DATABASE} is used as placeholder to store the database in a temporary location +The command has to exit. In case of `sftp` as last commend `exit` has to be sent + + por exemplo: +get DatabaseOnRemote.kdbx {TEMP_DATABASE} +exit +--- +{TEMP_DATABASE} é usado como espaço reservado para armazenar o banco de dados em um local temporário +O comando tem que sair. No caso de `sftp` como último comando `exit` deve ser enviado + + + Remote Database (.kdbx) + Banco de Dados Remoto (.kdbx) + KMessageWidget @@ -5561,12 +5989,6 @@ Esta versão não deve ser utilizada em ambientes de produção. Expect some bugs and minor issues, this version is meant for testing purposes. AVISO: você está usando uma versão de testes do KeePassXC! Pode encontrar erros graves e esta versão não deve ser utilizada em ambientes de produção. - - - WARNING: Your Qt version may cause KeePassXC to crash with an On-Screen Keyboard. -We recommend you use the AppImage available on our downloads page. - AVISO: Sua versão do Qt pode fazer com que o KeePassXC trave com um teclado na tela! -Recomendamos que você use o AppImage disponível em nossa página de downloads. No Tags @@ -5640,6 +6062,10 @@ Recomendamos que você use o AppImage disponível em nossa página de downloads. Import Passkey Importar Chave de Acesso + + Remote S&ync… + S&incronização Remota... + Quit Application Sair do Aplicativo @@ -5744,6 +6170,10 @@ Recomendamos que você use o AppImage disponível em nossa página de downloads. Show Password Generator Mostrar Gerador de Senhas + + Remove Passkey From Entry + Remover a chave de acesso da entrada + Perform Auto-Type: {USERNAME} Executar a Digitação Automática: {USERNAME} @@ -5888,6 +6318,34 @@ Recomendamos que você use o AppImage disponível em nossa página de downloads. Toggle Allow Screen Capture Alternar para Permitir Captura de Tela + + Show Group Panel + Mostrar Painel do Grupo + + + Toggle Show Group Panel + Alternar Exibição do Painel do Grupo + + + Setup Remote Sync… + Configurar Sincronização Remota... + + + Password Generator + Gerador de Senha + + + E&xpire Entry… + + + + Clear SSH Agent + Limpar agente SSH + + + Clear all identities in ssh-agent + + ManageDatabase @@ -6038,6 +6496,25 @@ Recomendamos que você use o AppImage disponível em nossa página de downloads. Por favor preencha o nome de exibição e uma descrição opcional para o seu novo banco de dados: + + NewEntryAttachmentsDialog + + Attachment name cannot be empty + O nome do anexo não pode estar vazio + + + Attachment with the same name already exists + Anexo com o mesmo nome já existe + + + Save attachment + Salvar anexo + + + New entry attachment + Novo anexo da entrada + + NixUtils @@ -6225,6 +6702,10 @@ Recomendamos que você use o AppImage disponível em nossa página de downloads. Unexpected EOF when writing private key EOF inesperado enquanto escrevendp a chave privada. + + (encrypted) + (criptografado) + OpenSSHKeyGenDialog @@ -6273,7 +6754,7 @@ Recomendamos que você use o AppImage disponível em nossa página de downloads. Export the following passkey entries. - + Exportar as seguintes chaves de acesso. @@ -6347,15 +6828,15 @@ Você deseja sobrescrevê-lo? Import the following passkey: - + importar as seguintes chaves de acesso: Import the following passkey to this entry: - + Importar as seguintes chaves de acesso para esta entrada: Default passkeys group (Imported Passkeys) - + Grupo de chaves de acesso padrão (chaves de acesso importadas) @@ -6378,25 +6859,27 @@ Você deseja sobrescrevê-lo? Open passkey file - + Abrir o arquivo da chave de acesso Cannot import passkey - + Não foi possível importar a chave de acesso Cannot import passkey file "%1". Data is missing. - + Não foi possível importar o arquivo da chave de acesso "%1". Faltam dados. Cannot import passkey file "%1". The following data is missing: %2 - + Não foi possível importar o arquivo da chave de acesso "%1". +Os seguintes dados estão faltando: +%2 Cannot import passkey file "%1". Private key is missing or malformed. - + Não foi possível importar o arquivo da chave de acesso "%1". A chave privada está ausente ou malformada. @@ -6577,10 +7060,6 @@ The following data is missing: Also choose from: Escolher também de: - - Excluded characters: "0", "1", "l", "I", "O", "|", "﹒" - Caracteres excluídos: "0", "1", "l", "I", "O", "|", "﹒" - Exclude look-alike characters Excluir caracteres semelhantes @@ -6605,10 +7084,6 @@ The following data is missing: Word Count: Número de Palavras: - - Character Count: - Número de Caracteres: - Word Case: Caixa da palavra: @@ -6621,10 +7096,6 @@ The following data is missing: Add custom wordlist Adicionar lista de palavras personalizada - - character - caractere - Close Fechar @@ -6731,6 +7202,22 @@ Tem certeza que deseja substitui-la? Special Characters Caracteres Especiais + + passwordLength + + + + Characters: %1 + Caracteres: %1 + + + MIXED case + + + + Excluded characters: "0", "1", "l", "I", "O", "|", "﹒", "B", "8", "G", "6" + Caracteres excluídos: '0', '1', 'l', 'I', 'O', '|', '﹒', 'B', '8', 'G', '6' + PasswordWidget @@ -6798,6 +7285,21 @@ Tem certeza que deseja substitui-la? Pressione &Tab entre os caracteres + + PreviewEntryAttachmentsDialog + + Preview entry attachment + + + + No preview available + Nenhuma prévia disponível + + + Image format not supported + Formato de imagem não suportado + + QMessageBox @@ -7476,10 +7978,6 @@ Tem certeza que deseja substitui-la? Invalid word count %1 Contador de palavra %1 inválido - - The word list is too small (< 1000 items) - A lista de palavras é muito pequena (<1000 itens) - Title for the entry. Título para a entrada. @@ -7624,10 +8122,6 @@ Tem certeza que deseja substitui-la? Exit interactive mode. Sair do modo interativo. - - Format to use when exporting. Available choices are 'xml' or 'csv'. Defaults to 'xml'. - Formato usado ao exportar. Escolhas disponíveis são 'xml' ou 'csv'. O padrão é 'xml'. - Exports the content of a database to standard output in the specified format. Exportar o conteúdo do banco de dados para um padrão de saída no formato especificado. @@ -8216,18 +8710,6 @@ Foi encontrada a versão %2.%3.%4 file empty arquivo vazio - - malformed string - sequência de caracteres malformada - - - missing closing quote - apóstrofo de fechamento ausente - - - %1: (row, col) %2,%3 - %1: (linha, coluna) %2,%3 - AES 256-bit AES 256-bit @@ -8471,11 +8953,12 @@ Foi encontrada a versão %2.%3.%4 Set the key file for the database. This option is deprecated, use --set-key-file instead. - + Define o arquivo da chave para o banco de dados. +Essa opção está obsoleta; em vez disso, use --set-key-file. Databases have been locked. - + Os bancos de dados foram trancados. Attestation not supported @@ -8672,13 +9155,89 @@ This option is deprecated, use --set-key-file instead. Atalhos - Unsupported KDF type, cannot decrypt json file + Unknown passkeys error + Chave de acesso com erro desconhecido + + + Invalid KDF iterations, cannot decrypt json file + Iterações KDF inválidas, não é possível descriptografar o arquivo json + + + Unsupported format, ensure your Bitwarden export is password-protected + Formato não suportado, certifique-se de que sua exportação Bitwarden esteja protegida por senha + + + Only PBKDF and Argon2 are supported, cannot decrypt json file + Apenas PBKDF e Argon2 são suportados, não é possível descriptografar o arquivo json + + + Reset Shortcuts + Redefinir Atalhos + + + Double click an action to change its shortcut + Clique duas vezes em uma ação para alterar seu atalho + + + Filter... + Filtro... + + + Shortcut Conflict + Conflito de Atalhos + + + Shortcut %1 conflicts with '%2'. Overwrite shortcut? + O atalho %1 está em conflito com '%2'. Substituir o atalho? + + + Cannot generate valid passphrases because the wordlist is too short + Não é possível gerar senhas válidas porque a lista de palavras é muito curta + + + Encrypted files are not supported. - Unknown passkeys error + Proton Pass Import + Importar do Proton Pass + + + Delete plugin data? + Apagar dados do plugin? + + + Delete plugin data from Entry(s)? + Excluir dados do plugin da Entrada?Excluir dados do plugin da(s) Entrada(s)?Excluir dados do plugin da(s) Entrada(s)? + + + Passkey + Chave de acesso + + + Format to use when exporting. Available choices are 'xml', 'csv' or 'html'. Defaults to 'xml'. + + start minimized to the system tray + iniciar minimizado na bandeja do sistema + + + malformed string, possible unescaped delimiter + + + + missing closing delimiter + + + + %1, row: %2, column: %3 + + + + Tags + Etiquetas + QtIOCompressor @@ -8714,6 +9273,37 @@ This option is deprecated, use --set-key-file instead. Erro interno do zlib: + + RemoteHandler + + Command `%1` did not finish in time. Process was killed. + + + + Failed to upload merged database. Command `%1` did not finish in time. Process was killed. + + + + Invalid download parameters provided. + Parâmetros de download inválidos fornecidos. + + + Command `%1` failed to download database. + + + + Invalid database pointer or upload parameters provided. + Ponteiro de banco de dados ou parâmetros de upload inválidos fornecidos. + + + Command `%1` exited with status code: %2 + + + + Failed to upload merged database. Command `%1` exited with status code: %2 + + + ReportsWidgetBrowserStatistics @@ -8780,6 +9370,10 @@ This option is deprecated, use --set-key-file instead. Exclude from reports Excluir dos relatórios + + Expire Entry(s)… + + Only show entries that have a URL Mostrar apenas entradas que tenham a URL @@ -8796,36 +9390,33 @@ This option is deprecated, use --set-key-file instead. (Expired) (Expirada) + + Delete plugin data from Entry(s)… + Excluir dados de plugin da Entrada...Excluir dados de plugin(s) da(s) Entrada(s)...Excluir dados de plugin(s) da(s) Entrada(s)... + ReportsWidgetHealthcheck - Hover over reason to show additional details. Double-click entries to edit. - Passe o mouse sobre o motivo para mostrar detalhes adicionais. Clique duas vezes nas entradas para editar. + Show expired entries + Mostrar entradas expiradas - Bad - Password quality - Ruim + (Expired) + (Expirada) + + + Hover over reason to show additional details. Double-click entries to edit. + Passe o mouse sobre o motivo para mostrar detalhes adicionais. Clique duas vezes nas entradas para editar. Bad — password must be changed Ruim — a senha precisa ser mudada - - Poor - Password quality - Pobre - Poor — password should be changed Pobre — a senha precisa ser mudada - - Weak - Password quality - Fraco - Weak — consider changing the password Fraca — considere mudar a senha @@ -8874,18 +9465,14 @@ This option is deprecated, use --set-key-file instead. Exclude from reports Excluir dos relatórios - - Show expired entries - Mostrar entradas expiradas + + Expire Entry(s)… + Show entries that have been excluded from reports Mostrar entradas que foram excluídas dos relatórios - - (Expired) - (Expirada) - ReportsWidgetHibp @@ -8981,6 +9568,10 @@ This option is deprecated, use --set-key-file instead. Exclude from reports Excluir dos relatórios + + Expire Entry(s)… + + ReportsWidgetPasskeys @@ -9042,11 +9633,11 @@ This option is deprecated, use --set-key-file instead. Please wait, list of entries with passkeys is being updated… - + Aguarde, a lista das entradas das chaves de acesso está sendo atualizada... No entries with passkeys. - + Não há entradas com chaves de acesso. @@ -9222,6 +9813,14 @@ This option is deprecated, use --set-key-file instead. No agent running, cannot list identities. Nenhum agente em execução, não é possível listar identidades. + + Failed to remove all SSH identities from agent. + + + + All SSH identities removed from agent. + + SearchHelpWidget @@ -9396,11 +9995,11 @@ This option is deprecated, use --set-key-file instead. <html><head/><body><p>This setting does not override disabling recycle bin prompts </p></body></html> - + <html><head/><body><p>Essa configuração não substitui a desativação dos avisos da lixeira </p></body></html> <html><head/><body><p>This improves compatibility with certain applications which search for password without unlocking the database first.</p><p>But enabling this may also crash the client if the database can not be unlocked within a certain timeout. (Usually 25s, but may be a different value set in applications.) </p></body></html> - + <html><head/><body><p>Isso melhora a compatibilidade com determinados aplicativos que buscam a senha sem antes desbloquear o banco de dados.<p>No entanto, esta ativação também pode travar o cliente se o banco de dados não puder ser desbloqueado dentro de um determinado limite de tempo. (Geralmente 25s, mas pode haver um valor diferente definido nos aplicativos.)</p></body></html> @@ -9507,29 +10106,6 @@ This option is deprecated, use --set-key-file instead. Exportar para %1 - - ShortcutSettingsWidget - - Double click an action to change its shortcut - Clique duas vezes em uma ação para alterar seu atalho - - - Shortcut Conflict - Conflito de Atalhos - - - Filter... - Filtro... - - - Shortcut %1 conflicts with '%2'. Overwrite shortcut? - O atalho %1 está em conflito com '%2'. Substituir o atalho? - - - Reset Shortcuts - Redefinir Atalhos - - TagModel @@ -9818,14 +10394,18 @@ Exemplo: JBSWY3DPEHPK3PXP No hardware keys detected Nenhuma chave física detectada - - <p>If you own a <a href="https://www.yubico.com/">YubiKey</a> or <a href="https://onlykey.io">OnlyKey</a>, you can use it for additional security.</p><p>The key requires one of its slots to be programmed as <a href="https://docs.yubico.com/yesdk/users-manual/application-otp/challenge-response.html">HMAC-SHA1 Challenge-Response</a>.</p> - <p>Se você possui um <a href="https://www.yubico.com/">YubiKey</a> ou <a href="https://onlykey.io">OnlyKey</a>, você pode usá-lo como uma segurança adicional.</p><p>A chave requer que um dos seus slots seja programado como <a href="https://docs.yubico.com/yesdk/users-manual/application-otp/challenge-response.html">HMAC-SHA1 Challenge-Response</a>.</p> - Refresh hardware keys Atualizar chaves de hardware + + <p>If you own a <a href="https://www.yubico.com/">YubiKey</a> or <a href="https://onlykey.io">OnlyKey</a>, you can use it for additional security.</p><p>The key requires one of its slots to be programmed with <a href="https://keepassxc.org/docs/#faq-yubikey-howto">Challenge-Response</a>.</p> + + + + Hardware keys found, but no slots are configured + + YubiKeyInterfacePCSC diff --git a/share/translations/keepassxc_pt_PT.ts b/share/translations/keepassxc_pt_PT.ts index 00fc3ec7e..f15877fe4 100644 --- a/share/translations/keepassxc_pt_PT.ts +++ b/share/translations/keepassxc_pt_PT.ts @@ -54,11 +54,11 @@ Non-existing/inaccessible executable path. Please double-check the client is legit. - O caminho do executável não existe ou não pode ser acedido. Deve verificar se a aplicação utilizada é legítima. + O caminho do executável não existente/acessível. Verifique se a aplicação utilizada é legítima. <html><head/><body><p><span style=" font-weight:600;">%1 </span>is requesting access to the following entries:</p></body></html> - <html><head/><body><p><span style=" font-weight:600;">%1 </span>está a solicitar acessos a estas entradas:</p></body></html> + <html><head/><body><p><span style=" font-weight:600;">%1 </span>está a solicitar acesso a estas entradas:</p></body></html> Name @@ -116,11 +116,11 @@ Use Pageant - Usar Pageant + Utilizar "Pageant" Use OpenSSH - Usar OpenSSH + Utilizar "OpenSSH" Use both agents @@ -152,7 +152,7 @@ SSH Agent connection is working! - A ligação ao agente SSH está a funcionar! + A ligação ao agente SSH está funcional! @@ -217,17 +217,49 @@ You must restart the application to set the new language. Would you like to restart now? Tem que reiniciar a aplicação para aplicar o novo idioma. Reiniciar agora? - - Reset Settings? - Repor definições? - - - Are you sure you want to reset all general and security settings to default? - Tem a certeza de que deseja repor todas as definições para os valores padrão? - Select backup storage directory - Selecione o diretório para a cópia de segurança + Selecione o diretório para o backup + + + Confirm Reset + Confirmação de reposição + + + Are you sure you want to reset all settings to default? + Tem a certeza de que pretende restaurar as definições padrão? + + + Import KeePassXC Settings + Importar definições KeePassXC + + + Failed to import settings from %1, not a valid settings file. + %1 não é um ficheiro válido e não foi possível importar as definições. + + + Export KeePassXC Settings + Exportar definições KeePassXC + + + Small + Pequeno + + + Normal + Normal + + + Medium + Médio + + + Large + Grande + + + Custom + Personalizado @@ -246,7 +278,7 @@ Automatically launch KeePassXC at system startup - Iniciar o KeePassXC ao arrancar o sistema + Iniciar KeePassXC no arranque do sistema operativo Minimize window at application startup @@ -266,7 +298,7 @@ Load previously open databases on startup - Ao iniciar, carregar as últimas bases de dados utilizadas + Ao iniciar, carregar últimas bases de dados utilizadas Remember database key files and security dongles @@ -280,25 +312,6 @@ Include beta releases when checking for updates Incluir versões beta ao procurar por atualizações - - On database unlock, show entries that - Ao desbloquear a base de dados, mostrar entradas que - - - have expired - On database unlock, show entries that... - caducaram - - - days - On database unlock, show entries that will expire within %1 days - dias - - - will expire within - On database unlock, show entries that... - irão caducar dentro de - File Management Gestão de ficheiros @@ -321,24 +334,12 @@ Backup database file before saving - Criar cópia de segurança da base de dados antes de guardar - - - Backup destination - Destino da cópia de segurança - - - Specifies the database backup file location. Occurrences of "{DB_FILENAME}" are replaced with the filename of the saved database without extension. {TIME:<format>} is replaced with the backup time, see https://doc.qt.io/qt-5/qdatetime.html#toString. <format> defaults to format string "dd_MM_yyyy_hh-mm-ss". - Especifica a localização para a cópia de segurança da base de dados. As ocorrências de "{DB_FILENAME}" serão substituídas pelo nome de ficheiro da base de dados exportada mas sem extensão. {TIME:<format>} será substituído pela hora da cópia de segurança. Consulte https://doc.qt.io/qt-5/qdatetime.html#toString. <format> Os valores padrão a utilizar serão "dd_MM_yyyy_hh-mm-ss". + Criar backup da base de dados antes de guardar {DB_FILENAME}.old.kdbx {DB_FILENAME}.antiga.kdbx - - Choose... - Escolher… - Use alternative saving method (may solve problems with Dropbox, Google Drive, GVFS, etc.) Utilizar um método de guardar alternativo (pode resolver problemas com Dropbox, Google Drive, GVFS, etc) @@ -377,7 +378,7 @@ Favicon download timeout: - Tempo limite para descarregar o ícone de favoritos: + Tempo limite para descarregar os ícones: Website icon download timeout in seconds @@ -430,19 +431,19 @@ Show a system tray icon - Mostrar ícone na bandeja do sistema + Mostrar ícone na área de notificação do sistema Tray icon type - Tipo de ícone na bandeja + Tipo de ícone na área de notificação Tray icon type: - Ícone na bandeja: + Ícone na área de notificação: Hide window to system tray when minimized - Ao minimizar, ocultar janela na bandeja do sistema + Ao minimizar, ocultar janela na área de notificação do sistema Reset settings to default… @@ -505,6 +506,71 @@ Remember last typed entry for: Memorizar última entrada digitada durante: + + On database unlock, show entries that will expire within + Ao desbloquear a base de dados, mostrar entradas que caduquem em + + + On database unlock, show entries that will expire within + Ao desbloquear a base de dados, mostrar entradas que caduquem em + + + days + number of days warning for password expiration + dias + + + Destination format: + Formato de destino: + + + <html><head/><body><p><span style=" font-weight:600;">{DB_FILENAME}</span> is replaced with the filename of the saved database without extension</p><p><span style=" font-weight:600;">{TIME:&lt;format&gt;}</span> is replaced with the specified time format (default: dd_MM_yyyy_hh-mm-ss)</p><p>See the User Guide for more details</p></body></html> + <html><head/><body><p><span style=" font-weight:600;">{DB_FILENAME}</span> é substituido pelo nome de ficheiro da base de dados guardada, mas sem extensão</p><p><span style=" font-weight:600;">{TIME:&lt;format&gt;}</span> é substituido pelo formato de data/hora especificado (padrão: dd_MM_yyyy_hh-mm-ss)</p><p>Consulte o guia de utilizador para mais informações</p></body></html> + + + Choose folder... + Escolha a pasta... + + + Show confirmation before moving entries to recycle bin + Mostrar diálogo de confirmação antes de mover entradas para a reciclagem + + + Copy data on double clicking field in entry view + Copiar dados ao clicar duas vezes no campo + + + Show toolbar + Mostrar barra de ferramentas + + + Show the menu bar by pressing the Alt key + Mostrar barra de menu ao premir a tecla ALT + + + Show menubar + Mostrar barra de menu + + + Import settings… + Importar definições... + + + Export settings… + Exportar definições... + + + Open browser on double clicking URL field in entry view + Abrir navegador ao clicar duas vezes no campo URL + + + Font size: + Tamanho do tipo de letra: + + + Font size selection + Seleção do tamanho do tipo de letra + ApplicationSettingsWidgetSecurity @@ -570,18 +636,6 @@ Hide passwords in the entry preview panel Ocultar palavras-passe no painel de pré-visualização de entradas - - Hide entry notes by default - Por definição, ocultar notas da entrada - - - Move entries to recycle bin without confirmation - Mover entradas para a reciclagem sem confirmação - - - Enable double click to copy the username/password entry columns - Ativar duplo clique para copiar a entrada nome de utilizador/palavra-passe - Privacy Privacidade @@ -594,12 +648,24 @@ Hide TOTP in the entry preview panel Ocultar TOTP no painel de pré-visualização + + Lock databases when switching user + Bloquear base de dados ao trocar de utilizador + + + Lock Options + Opções de bloqueio + + + Hide notes in the entry preview panel + Ocultar notas no painel de pré-visualização + AutoType The requested Auto-Type sequence cannot be used due to an error: - A sequência de escrita automática não pode ser utilizada por causa do seguinte erro: + A sequência de escrita automática não pode ser utilizada devido ao seguinte erro: Auto-Type Error @@ -611,15 +677,15 @@ KeePassXC requires the Accessibility permission in order to perform entry level Auto-Type. If you already granted permission, you may have to restart KeePassXC. - KeePassXC necessita da permissão 'Accessibility' para poder executar a escrita automática. Se já concedeu esta permissão, pode ser necessário reiniciar a aplicação. + KeePassXC necessita da permissão 'Acessibilidade' para executar a escrita automática. Se já concedeu esta permissão, pode ser necessário reiniciar a aplicação. KeePassXC requires the Accessibility and Screen Recorder permission in order to perform global Auto-Type. Screen Recording is necessary to use the window title to find entries. If you already granted permission, you may have to restart KeePassXC. - KeePassXC necessita das permissões 'Accessibility' e 'Screen Recorder' para poder executar a escrita automática. A permissão 'Screen recording' é necessária para associar o titulo da janela às entradas. Se já concedeu estas permissões, pode ser necessário reiniciar a aplicação. + KeePassXC necessita das permissões 'Acessibilidade' e 'Gravador de ecrã' para executar a escrita automática. A permissão 'Gravador de ecrã' é necessária para associar o titulo da janela às entradas. Se já concedeu estas permissões, pode ser necessário reiniciar a aplicação. Invalid entry provided - Disponibilizada uma entrada inválida + Indicou uma entrada inválida Bracket imbalance detected, found extra { or } @@ -641,20 +707,6 @@ Entry does not have attribute for PICKCHARS: %1 A entrada não tem o atributo para PICKCHARS: %1 - - Invalid conversion type: %1 - Tipo de conversão inválido: %1 - - - Invalid conversion syntax: %1 - Sintaxe de conversão inválida: %1 - - - Invalid regular expression syntax %1 -%2 - Sintaxe de expressão regular inválida %1 -%2 - Invalid placeholder: %1 Marcador de posição inválido: %1 @@ -706,7 +758,7 @@ Sequence aborted: Modifier keys held by user - Sequência abortada. Tecla modificadora premida pelo utilizador. + Sequência abortada: tecla modificadora premida pelo utilizador Unable to get valid keycode for key: @@ -735,7 +787,7 @@ Ctrl+2 - Type password<br/> Ctrl+3 - Type TOTP<br/> Ctrl+4 - Use Virtual Keyboard (Windows Only)</p> <p>Pode utilizar a pesquisa avançada para localizar as entradas nas base de dados abertas. Os atalhos abaixo podem ser úteis:<br/> -Ctrl+F - Alternar pesquisa nas bases de dados<br/> +Ctrl+F - Comutar pesquisa nas bases de dados<br/> Ctrl+1 - Escrever nome de utilizador<br/> Ctrl+2 - Escrever palavra-passe<br/> Ctrl+3 - Escrever TOTP<br/> @@ -751,7 +803,7 @@ Ctrl+4 - Utilizar teclado virtual (apenas Windows)</p> Type Sequence - Escrever sequência + Sequência Cancel @@ -886,24 +938,25 @@ Selecione a base de dados correta para guardar as credenciais. Add to existing entry - + Adicionar à entrada existente Existing passkey found. Do you want to register a new passkey for: - + Chave-mestra existente encontrada. +Pretende registar uma nova chave-mestra para: Select the existing passkey and press Update to replace it. - + Selecione a chave-mestra existente e prima "Atualizar" para a substituir. Authenticate passkey credentials for: - + Autenticar credenciais de chave-mestra para: Do you want to register a passkey for: - + Pretende registar uma chave-mestra para: @@ -946,7 +999,7 @@ Deseja substituir a chave existente? A request for deleting entry "%1" has been received. Do you want to delete the entry? - Recebido um pedido para a eliminação da entrada "%1". + Recebido um pedido para eliminar a entrada "%1". Deseja eliminar a entrada? @@ -988,16 +1041,17 @@ Deseja eliminar a entrada? Register a new passkey to this entry: - + Registar uma nova chave-mestra para esta entrada: KeePassXC - Update passkey - + KeePassXC - Atualizar chave-mestra Entry already has a passkey. Do you want to overwrite the passkey in %1 - %2? - + A entrada já tem uma chave-mestra. +Pretende substituir a chave-mestra em %1 - %2? Register @@ -1022,10 +1076,6 @@ Do you want to overwrite the passkey in %1 - %2? General Geral - - Browsers installed as snaps are currently not supported. - Ainda não existe suporte a navegadores no formato Snap - Enable integration for these browsers: Ativar integração para estes navegadores: @@ -1197,18 +1247,6 @@ Do you want to overwrite the passkey in %1 - %2? Custom extension ID ID da extensão personalizada - - Due to Snap sandboxing, you must run a script to enable browser integration.<br />You can obtain this script from %1 - Devido a 'Snap sandboxing', tem que executar um script para ativar a integração com o navegador.<br />Pode obter o script em %1 - - - KeePassXC-Browser is needed for the browser integration to work. <br />Download it for %1 and %2 and %3. %4 - Necessita de KeePassXC-Browser para que a integração funcione corretamente.<br /> Disponível para %1, %2 e %3. %4 - - - Please see special instructions for browser extension use below - Por favor consulte abaixo as instruções para a utilização da extensão - Executable Files Ficheiros executáveis @@ -1251,11 +1289,19 @@ Do you want to overwrite the passkey in %1 - %2? Allows using insecure http://localhost with passkeys for testing purposes. - + Permite utilizar http://localhost inseguro com chaves-mestras para efeitos de teste. Allow using localhost with passkeys - + Permitir utilização de "localhost" com chaves-mestras + + + KeePassXC-Browser is needed for the browser integration to work. <br />Download it for %1 and %2 and %3. + Requer KeePassXC-Browser para que a integração com o navegador de Internet funcione. <br />Descarregue-o para %1 e %2 e %3. + + + Browsers installed using Snap or Flatpak are not supported with exception to Firefox installed using Snap. + Com exceção do Firefox Snap, quaisquer navegadores instalados na forma de Snap ou Flatpak não são suportados. @@ -1399,6 +1445,20 @@ Do you want to overwrite the passkey in %1 - %2? Imported from CSV file: %1 Importado do ficheiro CSV: %1 + + No Title Selected + Nenhum título selecionado + + + No title column was selected, entries will be hard to tell apart. +Are you sure you want to import? + Não selecionou um título de coluna e, assim, será difícil distinguir as entradas. +Tem a certeza de que pretende continuar com a importação? + + + Tags + Etiquetas + CsvParserModel @@ -1452,7 +1512,7 @@ Do you want to overwrite the passkey in %1 - %2? %1 Backup database located at %2 %1 -Cópia de segurança localizada em %2 +Backup localizada em %2 Key not transformed. This is a bug, please report it to the developers. @@ -1462,6 +1522,14 @@ Cópia de segurança localizada em %2 Recycle Bin Reciclagem + + Database file read error. + Erro de leitura do ficheiro da base de dados. + + + No file path was provided. + Não indicou o caminho do ficheiro. + DatabaseOpenDialog @@ -1600,7 +1668,7 @@ Para impedir que este erro surja novamente, deve aceder a "Definições da Failed to authenticate with Quick Unlock: %1 - Não foi possível autenticar com Quick Unlock: %1 + Não foi possível autenticar com desbloqueio rápido: %1 Select Key File: @@ -1610,14 +1678,6 @@ Para impedir que este erro surja novamente, deve aceder a "Definições da <p>In addition to a password, you can use a secret file to enhance the security of your database. This file can be generated in your database's security settings.</p><p>This is <strong>not</strong> your *.kdbx database file!</p> <p>Além de uma palavra-passe, pode utilizar um ficheiro secreto para melhorar a segurança da sua base de dados. Este ficheiro pode ser gerado nas definições de segurança da sua base de dados.</p><p>Este <strong>não</strong> é o seu ficheiro de base de dados *.kdbx!</p> - - Click to add a key file. - Clique para adicionar um ficheiro-chave. - - - <a href="#" style="text-decoration: underline">I have a key file</a> - <a href="#" style="text-decoration: underline">Eu tenho um ficheiro-chave</a> - Use hardware key [Serial: %1] Utilizar chave de hardware [Nº de série: %1] @@ -1654,6 +1714,18 @@ Tem a certeza de que pretende continuar com este ficheiro? Refresh Hardware Keys Recarregar chaves de hardware + + Click to add a key file. + Clique para adicionar um ficheiro-chave. + + + <a href="#" style="text-decoration: underline">I have a key file</a> + <a href="#" style="text-decoration: underline">Eu tenho um ficheiro-chave</a> + + + Hardware keys found, but no slots are configured. + A chave física foi encontrada mas não está configurada. + DatabaseSettingWidgetMetaData @@ -1688,6 +1760,22 @@ Tem a certeza de que pretende continuar com este ficheiro? Maintenance Manutenção + + KeeShare + KeeShare + + + Secret Service Integration + Integração 'Secret Service' + + + Remote Sync + Sincronização remota + + + Database Settings: %1 + Definições da base de dados: %1 + DatabaseSettingsWidgetBrowser @@ -1713,7 +1801,7 @@ Tem a certeza de que pretende continuar com este ficheiro? Stored browser keys - Chaves armazenadas + Chaves do navegador guardadas Remove selected key @@ -1725,12 +1813,12 @@ Tem a certeza de que pretende continuar com este ficheiro? Delete the selected key? - Apagar chave selecionada? + Eliminar chave selecionada? Do you really want to delete the selected key? This may prevent connection to the browser plugin. - Tem a certeza de que deseja apagar a chave selecionada? + Tem a certeza de que deseja eliminar a chave selecionada? Esta ação pode impedir a ligação ao suplemento. @@ -1858,14 +1946,14 @@ Tem a certeza de que deseja continuar? Weak password Palavra-passe fraca - - You must enter a stronger password to protect your database. - Tem que introduzir uma palavra-passe mais segura para proteger a sua base de dados. - This is a weak password! For better protection of your secrets, you should choose a stronger password. Esta palavra-passe é insegura. Para proteger os seus segredos, deve utilizar uma palavra-passe mais segura. + + The provided password does not meet the minimum quality requirement. + A palavra-passe indicada não cumpre os requisitos mínimos de qualidade. + DatabaseSettingsWidgetEncryption @@ -1891,7 +1979,7 @@ Tem a certeza de que deseja continuar? Format cannot be changed: Your database uses KDBX 4 features - O formato não pode ser alterado. A base de dados utiliza recursos KDBX 4. + O formato não pode ser alterado: a base de dados utiliza recursos KDBX 4. Unless you need to open your database with other programs, always use the latest format. @@ -2041,7 +2129,7 @@ Se mantiver este número, a sua base de dados pode ser desbloqueada muito facilm DatabaseSettingsWidgetGeneral Database Metadata - Meta-dados da base de dados + Metadados da base de dados Database name: @@ -2114,10 +2202,10 @@ Esta ação é irreversível. the oldest history items of an entry will be removed such that only the specified amount of entries remain at most. - Ao guardar esta definição ou editar uma entrada -os itens mais antigos da história de uma entrada serão -removidos de tal forma que apenas o número máximo especificado -das entradas permanecem. + Ao guardar esta definição ou editar uma entrada, +os itens mais antigos do histórico de uma entrada +serão removidos e apenas o número máximo +especificado das entradas permanecem. Limit the amount of history items per entry to: @@ -2128,10 +2216,10 @@ das entradas permanecem. the oldest history items of an entry will be removed such that the remaining history items add up to the specified amount at most. - Ao guardar esta definição ou editar uma entrada -os itens mais antigos da história de uma entrada serão -removidos de tal forma que os itens de história restantes -somam ao máximo do número especificado. + Ao guardar esta definição ou editar uma entrada, +os itens mais antigos do histórico de uma entrada +serão removidos de modo a que os itens de histórico +sejam adicionados, no máximo, até ao valor especificado. Limit the total size of history items per entry to: @@ -2167,6 +2255,50 @@ removidas da base de dados. Autosave delay since last change checkbox Atraso para gravação automática após a última alteração da caixa de seleção + + Public Database Metadata + Metadados públicos da base de dados + + + Warning: the following settings are not encrypted. + Aviso: as definições seguintes não serão cifradas. + + + Display name: + Nome mostrado: + + + Publically visible display name used on the unlock dialog + Nome mostrado no diálogo de desbloqueio + + + Database public display name + Nome público da base de dados: + + + Display color: + Cor mostrada: + + + Publically visible color used on the unlock dialog + Cor exibida no diálogo de desbloqueio + + + Database public display color chooser + Seletor de cores para a base de dados + + + Clear + Limpar + + + Display icon: + Ícone mostrado: + + + Select Database Icon + Selecione o ícone da base de dados + DatabaseSettingsWidgetKeeShare @@ -2262,6 +2394,140 @@ removidas da base de dados. Campo Descrição da base de dados + + DatabaseSettingsWidgetRemote + + Sync Commands + Comandos de sincronização + + + Remove + Remover + + + Command Settings + Definições do comando + + + Name + Nome + + + Save + Guardar + + + Download + Descarregar + + + Command: + Comando: + + + Download command field + Campo de comando de descargas + + + e.g.: "sftp user@hostname" or "scp user@hostname:DatabaseOnRemote.kdbx {TEMP_DATABASE}" + por exemplo: "sftp user@hostname" ou "scp user@hostname:DatabaseOnRemote.kdbx {TEMP_DATABASE}" + + + Input: + Entrada: + + + Download input field + Campo de entrada para descargas + + + Upload + Carregar + + + Upload command field + Campo de comando para envio + + + e.g.: "sftp user@hostname" or "scp {TEMP_DATABASE} user@hostname:DatabaseOnRemote.kdbx" + por exemplo: "sftp user@hostname" ou "scp {TEMP_DATABASE} user@hostname:DatabaseOnRemote.kdbx" + + + Upload input field + Campo de introdução de carregamento + + + Name cannot be empty. + O nome não pode estar vazio. + + + Test + Testar + + + Download command cannot be empty. + O comando de descarga não pode estar vazio. + + + Download failed with error: %1 + A descarga falhou com o erro: %1 + + + Download finished, but file %1 could not be found. + A descarga foi concluída, mas não foi possível encontrar o ficheiro %1. + + + Download successful. + Descarga efetuada + + + Save Remote Settings + Guardar definições remotas + + + You have unsaved changes. Do you want to save them? + Tem alterações por guardar. Pretende guardá-las? + + + e.g.: +get DatabaseOnRemote.kdbx {TEMP_DATABASE} +exit +--- +{TEMP_DATABASE} is used as placeholder to store the database in a temporary location +The command has to exit. In case of `sftp` as last command `exit` has to be sent + + por exemplo: +get DatabaseOnRemote.kdbx {TEMP_DATABASE} +exit +--- +{TEMP_DATABASE} é utilizado como marcador de posição para guardar a base de dados numa localização temporária +O comando tem que ser bem sucedido. No caso do 'sftp', o último comando 'exit' tem de ser enviado + + + + e.g.: +put {TEMP_DATABASE} DatabaseOnRemote.kdbx +exit +--- +{TEMP_DATABASE} is used as placeholder to store the database in a temporary location +The command has to exit. In case of `sftp` as last command `exit` has to be sent + + por exemplo: +coloque {TEMP_DATABASE} DatabaseOnRemote.kdbx +sair +--- +{TEMP_DATABASE} é usado como espaço reservado para armazenar o banco de dados em um local temporário +O comando tem que sair. No caso de `sftp` como último comando `exit` deve ser enviado + + + Timeout: + Tempo limite: + + + seconds + segundos + + DatabaseTabWidget @@ -2335,6 +2601,11 @@ Existe aqui um erro que deve ser reportado aos programadores. Database tab name modifier %1 [Bloqueada] + + %1 [Temporary] + Database tab name modifier + %1 [temporário] + DatabaseWidget @@ -2372,11 +2643,11 @@ Existe aqui um erro que deve ser reportado aos programadores. Delete group - Apagar grupo + Eliminar grupo Do you really want to delete the group "%1" for good? - Tem a certeza de que deseja apagar permanentemente o grupo "%1"? + Tem a certeza de que deseja eliminar permanentemente o grupo "%1"? Move group to recycle bin? @@ -2458,26 +2729,6 @@ Guardar alterações? File has changed Ficheiro alterado - - The database file has changed. Do you want to load the changes? - O ficheiro da base de dados foi alterado. Deseja carregar as alterações? - - - Merge Request - Pedido de combinação - - - The database file has changed and you have unsaved changes. -Do you want to merge your changes? - A base de dados foi alterada e tem alterações não guardadas -Deseja combinar as suas alterações? - - - Could not open the new database file while attempting to autoreload. -Error: %1 - Não foi possível abrir a nova base de dados durante o carregamento -Erro: %1 - Disable safe saves? Desativar salvaguardas? @@ -2506,7 +2757,7 @@ Desativar salvaguardas e tentar novamente? Save database backup - Guardar cópia de segurança da base de dados + Guardar backup da base de dados Empty recycle bin? @@ -2514,11 +2765,11 @@ Desativar salvaguardas e tentar novamente? Are you sure you want to permanently delete everything from your recycle bin? - Tem a certeza de que deseja apagar permanentemente os itens da reciclagem? + Tem a certeza de que deseja eliminar permanentemente os itens da reciclagem? Could not find database file: %1 - Não foi possível encontrar a base de dados: %1 + Não foi possível encontrar o ficheiro da base de dados: %1 New Database @@ -2529,6 +2780,86 @@ Desativar salvaguardas e tentar novamente? Database tab name modifier %1 [Nova base de dados] + + Remote Sync did not contain any download or upload commands. + A sincronização remota não continha quaisquer comandos de descarga ou carregamento. + + + Remote sync '%1' completed successfully! + A sincronização remota '%1' foi concluída com sucesso! + + + Remote sync '%1' failed: %2 + A sincronização remota '%1' falhou: %2 + + + Error while saving database %1: %2 + Erro ao guardar a base de dados %1: %2 + + + Downloading... + A descarregar... + + + Uploading... + A carregar... + + + Syncing... + A sincronizar... + + + Remove passkey from entry + Remover chave-mestra da entrada + + + Do you want to remove the passkey from this entry? + Deseja remover a chave-mestra desta entrada? + + + The database file "%1" was modified externally + O ficheiro da base de dados "%1" foi alterado externamente + + + Do you want to load the changes? + Deseja carregar as alterações? + + + Reload database + Recarregar base de dados + + + Reloading database… + A recarregar base de dados… + + + Reload canceled + Recarga cancelada + + + Reload successful + Recarga efetuada + + + Reload pending user action… + Recarga pendente de uma ação do utilizador… + + + The database file "%1" was modified externally.<br>How would you like to proceed?<br><br>Merge all changes<br>Ignore the changes on disk until save<br>Discard unsaved changes + O ficheiro da base de dados "%1" foi alterado externamente.<br>Como pretende continuar?<br><br>Combinar todas as alterações<br>Ignorar alterações no disco até guardar<br>Descartar alterações não guardadas + + + The database file "%1" was modified externally.<br>How would you like to proceed?<br><br>Merge all changes then save<br>Overwrite the changes on disk<br>Discard unsaved changes + O ficheiro da base de dados "%1" foi alterado externamente.<br>Como pretende continuar?<br><br>Combinar todas as alterações e guardar<br>Substituir alterações no disco<br>Descartar alterações não guardadas + + + Database file overwritten. + Ficheiro de base de dados substituído. + + + Database file on disk cannot be unlocked with current credentials.<br>Enter new credentials and/or present hardware key to continue. + O ficheiro da base de dados no disco não pode ser desbloqueado com as credenciais atuais.<br>Introduza as novas credenciais e/ou a chave de hardware para continuar. + EditEntryWidget @@ -2580,10 +2911,6 @@ Desativar salvaguardas e tentar novamente? n/a n/d - - (encrypted) - (cifrada) - Select private key Selecionar chave privada @@ -2630,7 +2957,7 @@ Gostaria de a corrigir? An error occurred while validating the Auto-Type sequence for "%1": %2 Would you like to correct it? - Ocorreu um erro ao validar a sequência personalizada de escrita automática para %1. + Ocorreu um erro ao validar a sequência personalizada de escrita automática para "%1". %2 Gostaria de a corrigir? @@ -2664,7 +2991,7 @@ Gostaria de a corrigir? [PROTECTED] Press Reveal to view or edit - [PROTEGIDO] Use o botão 'Mostrar' para ver ou editar + [PROTEGIDO] Utilize o botão 'Mostrar' para ver ou editar Hide @@ -2686,6 +3013,10 @@ Gostaria de a corrigir? %n year(s) %n ano%n anos%n anos + + Failed to decrypt SSH key, ensure password is correct. + Falha ao decifrar a chave SSH, verifique se a palavra-passe está correta. + EditEntryWidgetAdvanced @@ -2727,7 +3058,7 @@ Gostaria de a corrigir? Toggle attribute protection - Alternar proteção do atributo + Comutar proteção do atributo Protect @@ -2747,7 +3078,7 @@ Gostaria de a corrigir? If checked, the entry will not appear in reports like Health Check and HIBP even if it doesn't match the quality requirements. - Se marcado, a entrada não aparecerá em relatórios como Health Check e HIBP, mesmo que não corresponda aos requisitos de qualidade. + Se ativa, a entrada não aparecerá em relatórios como Health Check e HIBP, mesmo que não corresponda aos requisitos de qualidade. Exclude from database reports @@ -2857,18 +3188,10 @@ Gostaria de a corrigir? Skip Auto-Submit for this entry Ignorar submissão automática para esta entrada - - Only send this setting to the browser for HTTP Auth dialogs. If enabled, normal login forms will not show this entry for selection. - Apenas enviar esta definição para o navegador em diálogos HTTP Auth. Se ativa, os formulários normais de acesso não mostrarão esta entrada para seleção. - Use this entry only with HTTP Basic Auth Apenas utilizar esta entrada com HTTP Basic Auth - - Do not send this setting to the browser for HTTP Auth dialogs. If enabled, HTTP Auth dialogs will not show this entry for selection. - Não enviar esta definição para o navegador em diálogos de HTTP Auth. Se ativa, as caixas de diálogo HTTP Auth não mostrarão esta entrada. - Do not use this entry with HTTP Basic Auth Não utilizar esta entrada com HTTP Basic Auth @@ -2891,7 +3214,15 @@ Gostaria de a corrigir? Additional URLs - URLs adicionais + URL adicionais + + + Only send this entry to the browser for HTTP Auth dialogs. If enabled, normal login forms will not show this entry for selection. + Enviar esta entrada ao navegador apenas para diálogos de autenticação HTTP. Se ativa, esta entrada não aparecerá nos formulários normais de autenticação. + + + Do not send this entry to the browser for HTTP Auth dialogs. If enabled, HTTP Auth dialogs will not show this entry for selection. + Não enviar esta entrada ao navegador apenas para diálogos de autenticação HTTP. Se ativa, esta entrada não aparecerá nos de autenticação HTTP. @@ -2918,19 +3249,19 @@ Gostaria de a corrigir? Delete selected history state - Apagar estado do histórico selecionado + Eliminar estado do histórico selecionado Delete - Apagar + Eliminar Delete all history - Apagar todo o histórico + Eliminar todo o histórico Delete all - Apagar tudo + Eliminar tudo @@ -2969,7 +3300,7 @@ Gostaria de a corrigir? Download favicon for URL - Descarregar ícone de um URL + Descarregar ícone deste URL Title field @@ -2981,7 +3312,7 @@ Gostaria de a corrigir? Toggle expiration - Alternar caducidade + Comutar caducidade Tags list @@ -3009,7 +3340,7 @@ Gostaria de a corrigir? Toggle notes visibility - Alternar exibição das notas + Comutar exibição das notas T&ags: @@ -3115,6 +3446,10 @@ Gostaria de a corrigir? seconds segundos + + Clear agent + Limpar agente + EditGroupWidget @@ -3175,7 +3510,7 @@ Gostaria de a corrigir? Skip Auto-Submit for entries: - Ignorar submissão automática para as entredas: + Ignorar submissão automática para as entradas: Skip Auto-Submit toggle for this and sub groups @@ -3211,7 +3546,7 @@ Gostaria de a corrigir? Restrict matching to given browser key toggle for this and sub groups - Restringir a correspondência a uma determinada chave do navegador para este e subgrupos + Restringir a correspondência a uma determinada chave do navegador para este e os seus subgrupos @@ -3332,7 +3667,7 @@ As extensões suportadas são: %1. Toggle expiration - Alternar caducidade + Comutar caducidade Expires: @@ -3407,11 +3742,11 @@ As extensões suportadas são: %1. Favicon URL - URL do ícone de favoritos + URL do ícone Download favicon for URL - Descarregar ícone de um URL + Descarregar ícone deste URL Download favicon @@ -3443,7 +3778,7 @@ As extensões suportadas são: %1. Unable to fetch favicon. - Não foi possível obter o ícone de favoritos + Não foi possível obter o ícone Existing icon selected. @@ -3534,12 +3869,12 @@ As extensões suportadas são: %1. Delete plugin data? - Apagar dados do suplemento? + Eliminar dados do suplemento? Do you really want to delete the selected plugin data? This may cause the affected plugins to malfunction. - Tem a certeza de que deseja apagar os dados do suplemento? + Tem a certeza de que deseja Eliminar os dados do suplemento? Esta ação pode implicar um funcionamento errático. @@ -3557,12 +3892,45 @@ Esta ação pode implicar um funcionamento errático. %1 - Clone %1 - Clone + + Passkey + Chave-mestra + + + Invalid conversion type: %1 + Tipo de conversão inválido: %1 + + + Invalid conversion syntax: %1 + Sintaxe de conversão inválida: %1 + + + Invalid regular expression syntax %1 +%2 + Sintaxe de expressão regular inválida %1 +%2 + EntryAttachments Cannot open file "%1" - Não foi possível abrir o ficheiro %1 + Não foi possível abrir o ficheiro "%1" + + + + EntryAttachmentsDialog + + Form + Formulário + + + File name + Nome do ficheiro + + + File contents... + Conteúdo do ficheiro... @@ -3602,14 +3970,6 @@ Esta ação pode implicar um funcionamento errático. Remove Remover - - Rename selected attachment - Mudar nome do anexo selecioando - - - Rename - Mudar nome - Open selected attachment Abrir anexo selecionado @@ -3726,6 +4086,18 @@ Would you like to overwrite the existing attachment? O anexo "%1" já existe Deseja substituir o anexo existente? + + New + Novo + + + Preview + Pré-visualização + + + Failed to preview an attachment: Attachment not found + Falha ao pré-visualizar: anexo não encontrado + EntryAttributesModel @@ -3924,6 +4296,10 @@ Deseja substituir o anexo existente? Background Color Cor de fundo + + Group Path + Caminho do grupo + EntryPreviewWidget @@ -4233,7 +4609,7 @@ As suas palavras-passe e informações pessoais ficarão vulneráveis! IconDownloaderDialog Download Favicons - Descarregar ícone de favoritos + Descarregar ícones Cancel @@ -4242,7 +4618,7 @@ As suas palavras-passe e informações pessoais ficarão vulneráveis! Having trouble downloading icons? You can enable the DuckDuckGo website icon service in the security section of the application settings. - Problemas para descarregar ícones? + Problemas ao descarregar os ícones? Pode ativar o serviço DuckDuckGo na secção 'Segurança' das definições. @@ -4279,7 +4655,7 @@ Pode ativar o serviço DuckDuckGo na secção 'Segurança' das defini Downloading favicons (%1/%2)… - A descarregar o ícone de favoritos (%1/%2)… + A descarregar o ícone (%1/%2)… @@ -4319,6 +4695,14 @@ Pode ativar o serviço DuckDuckGo na secção 'Segurança' das defini Url URL + + Could not load key file. + Não foi possível carregar o ficheiro-chave. + + + Could not open remote database. Password or key file may be incorrect. + Não foi possível abrir a base de dados remota. Palavra-passe ou ficheiro-chave inválidos. + ImportWizardPageSelect @@ -4422,6 +4806,50 @@ Pode ativar o serviço DuckDuckGo na secção 'Segurança' das defini KeePass1 Database Base de dados KeePass 1 + + Proton Pass (.json) + Proton Pass (.json) + + + Proton Pass JSON Export + Exportação JSON para Proton Pass + + + Temporary Database + Base de dados temporária + + + Command: + Comando: + + + e.g.: "sftp user@hostname" or "scp user@hostname:DatabaseOnRemote.kdbx {TEMP_DATABASE}" + por exemplo: "sftp user@hostname" or "scp user@hostname:DatabaseOnRemote.kdbx {TEMP_DATABASE}" + + + Input: + Entrada: + + + e.g.: +get DatabaseOnRemote.kdbx {TEMP_DATABASE} +exit +--- +{TEMP_DATABASE} is used as placeholder to store the database in a temporary location +The command has to exit. In case of `sftp` as last commend `exit` has to be sent + + eexemplo: +get DatabaseOnRemote.kdbx {TEMP_DATABASE} +exit +--- +{TEMP_DATABASE} é utilizado como marcador de posição para guardar a base de dados numa localização temporária +O comando tem que terminar (exit). No caso de `sftp` o último comando tem que ser `exit`. + + + + Remote Database (.kdbx) + Base de dados remota (.kdbx) + KMessageWidget @@ -5295,7 +5723,7 @@ Tem a certeza de que deseja utilizar este ficheiro? &Delete Entry… - Apagar entra&da… + Eliminar entra&da… &New Group… @@ -5307,11 +5735,11 @@ Tem a certeza de que deseja utilizar este ficheiro? &Delete Group… - Apagar g&rupo… + Eliminar g&rupo… Download All &Favicons… - Descarregar todos os ícones de &favoritos… + Descarregar &todos os ícones… Sort &A-Z @@ -5371,7 +5799,7 @@ Tem a certeza de que deseja utilizar este ficheiro? Download &Favicon - Descarregar ícone de &favoritos + &Descarregar ícone Open &URL @@ -5451,11 +5879,11 @@ Tem a certeza de que deseja utilizar este ficheiro? &Getting Started - &Iniciação + &Introdução Open Getting Started Guide - Abrir guia de iniciação + Abrir guia de introdução &Online Help @@ -5475,7 +5903,7 @@ Tem a certeza de que deseja utilizar este ficheiro? Save Database Backup… - Guardar cópia de segurança da base de dados… + Guardar backup da base de dados… Add key to SSH Agent @@ -5554,7 +5982,7 @@ Tem a certeza de que deseja utilizar este ficheiro? There is a high risk of corruption, maintain a backup of your databases. This version is not meant for production use. AVISO: está a utilizar uma versão instável do KeePassXC! -Existe um risco elevado de corrupção de ficheiros. Deve criar uma cópia de segurança da base de dados. +Existe um risco elevado de corrupção de ficheiros. Deve criar um backup da base de dados. Esta versão não deve ser utilizada em ambientes de produção. @@ -5562,12 +5990,6 @@ Esta versão não deve ser utilizada em ambientes de produção. Expect some bugs and minor issues, this version is meant for testing purposes. AVISO: está a utilizar uma versão de testes do KeePassXC! Pode encontrar erros graves e esta versão não deve ser utilizada em ambientes de produção. - - - WARNING: Your Qt version may cause KeePassXC to crash with an On-Screen Keyboard. -We recommend you use the AppImage available on our downloads page. - AVISO: a versão Qt do seu sistema pode causar o encerramento do KeePassXC se estiver a utilizar o teclado no ecrã (On-Screen Keyboard)! -Recomendamos que utilize a versão AppImage disponível no nosso site. No Tags @@ -5595,7 +6017,7 @@ Recomendamos que utilize a versão AppImage disponível no nosso site. Toggle window - Alternar janela + Comutar janela Quit KeePassXC @@ -5641,6 +6063,10 @@ Recomendamos que utilize a versão AppImage disponível no nosso site.Import Passkey Importar chave-mestra + + Remote S&ync… + S&incronização remota... + Quit Application Sair da aplicação @@ -5687,7 +6113,7 @@ Recomendamos que utilize a versão AppImage disponível no nosso site. Download All Favicons - Descarregar todos os 'favicons' + Descarregar todos os ícones Sort Groups A-Z @@ -5745,6 +6171,10 @@ Recomendamos que utilize a versão AppImage disponível no nosso site.Show Password Generator Mostrar gerador de palavras-passe + + Remove Passkey From Entry + Remover a chave-mestra da entrada + Perform Auto-Type: {USERNAME} Executar escrita automática: {USERNAME} @@ -5827,7 +6257,7 @@ Recomendamos que utilize a versão AppImage disponível no nosso site. Save Database Backup - Guardar cópia de segurança da base de dados + Guardar backup da base de dados SSH Agent: Add Key @@ -5839,7 +6269,7 @@ Recomendamos que utilize a versão AppImage disponível no nosso site. Toggle Compact Mode - Alternar "Modo compacto" + Comutar "Modo compacto" Set Theme: Automatic @@ -5859,27 +6289,27 @@ Recomendamos que utilize a versão AppImage disponível no nosso site. Toggle Show Menubar - Alternar mostrar barra de menus + Comutar "Mostrar barra de menus" Toggle Show Toolbar - Alternar "Mostrar barra de ferramentas" + Comutar "Mostrar barra de ferramentas" Toggle Show Preview Panel - Alternar "Mostrar painel de pré-visualização" + Comutar "Mostrar painel de pré-visualização" Toggle Always on Top - Alternar "Sempre na frente" + Comutar "Sempre na frente" Toggle Hide Usernames - Alternar "Ocultar nome de utilizador" + Comutar "Ocultar nome de utilizador" Toggle Hide Passwords - Alternar "Ocultar palavras-passe" + Comutar "Ocultar palavras-passe" Export to XML @@ -5887,7 +6317,35 @@ Recomendamos que utilize a versão AppImage disponível no nosso site. Toggle Allow Screen Capture - Alternar "Permitir captura de ecrã" + Comutar "Permitir captura de ecrã" + + + Show Group Panel + Mostrar painel Grupo + + + Toggle Show Group Panel + Comutar exibição do painel Grupo + + + Setup Remote Sync… + Configurar a sincronização remota… + + + Password Generator + Gerador de palavras-passe + + + E&xpire Entry… + E&xpirar entrada… + + + Clear SSH Agent + Limpar agente SSH + + + Clear all identities in ssh-agent + Limpar todas as identidades no ssh-agent @@ -5964,7 +6422,7 @@ Recomendamos que utilize a versão AppImage disponível no nosso site. Changed deleted objects - Objetos apagados alterados + Objetos elimnados alterados Adding missing icon %1 @@ -6039,6 +6497,25 @@ Recomendamos que utilize a versão AppImage disponível no nosso site.Preencha o nome e uma descrição adicional para a sua nova base de dados: + + NewEntryAttachmentsDialog + + Attachment name cannot be empty + O nome do anexo não pode estar vazio + + + Attachment with the same name already exists + Já existe um anexo com este nome + + + Save attachment + Guardar anexo + + + New entry attachment + Anexo da nova entrada + + NixUtils @@ -6226,6 +6703,10 @@ Recomendamos que utilize a versão AppImage disponível no nosso site.Unexpected EOF when writing private key EOF inesperado ao escrever a chave privada + + (encrypted) + (cifrada) + OpenSSHKeyGenDialog @@ -6274,7 +6755,7 @@ Recomendamos que utilize a versão AppImage disponível no nosso site. Export the following passkey entries. - + Exportar as seguintes entradas de chaves-mestras. @@ -6297,7 +6778,7 @@ Deseja substituir o ficheiro existente? Cannot open file "%1" for writing. - Não foi possível abrir o ficheiro %1 para escrita + Não foi possível abrir o ficheiro "%1" para escrita Cannot write to file @@ -6348,15 +6829,15 @@ Deseja substituir o ficheiro existente? Import the following passkey: - + Importar a seguinte chave-mestra: Import the following passkey to this entry: - + Importar a seguinte chave-mestra para esta entrada: Default passkeys group (Imported Passkeys) - + Grupo de chaves-mestras predefinidas (chaves-mestras importadas) @@ -6375,29 +6856,31 @@ Deseja substituir o ficheiro existente? Cannot open file "%1" for reading. - Não foi possível abrir o ficheiro %1 para leitura + Não foi possível abrir o ficheiro "%1" para leitura. Open passkey file - + Abrir o ficheiro da chave-mestra Cannot import passkey - + Não é possível importar a chave-mestra Cannot import passkey file "%1". Data is missing. - + Não é possível importar o ficheiro da chave-mestra "%1". Os dados estão em falta. Cannot import passkey file "%1". The following data is missing: %2 - + Não é possível importar o ficheiro da chave-mestra "%1". +Faltam os seguintes dados: +%2 Cannot import passkey file "%1". Private key is missing or malformed. - + Não é possível importar o ficheiro da chave-mestra "%1". A chave privada está em falta ou malformada. @@ -6408,7 +6891,7 @@ The following data is missing: Password field - Campo Palavra-passe + Campo palavra-passe Confirm password: @@ -6416,7 +6899,7 @@ The following data is missing: Repeat password field - Campo Repetição de palavra-passe + Campo repetição de palavra-passe Password @@ -6578,10 +7061,6 @@ The following data is missing: Also choose from: Escolher também de: - - Excluded characters: "0", "1", "l", "I", "O", "|", "﹒" - Caracteres excluídos: "0", "1", "l", "I", "O", "|", "﹒" - Exclude look-alike characters Excluir caracteres semelhantes @@ -6606,10 +7085,6 @@ The following data is missing: Word Count: Número de palavras: - - Character Count: - Número de caracteres: - Word Case: Tipo de letra: @@ -6622,10 +7097,6 @@ The following data is missing: Add custom wordlist Adicionar lista personalizada - - character - carácter - Close Fechar @@ -6726,12 +7197,28 @@ Tem a certeza de que a deseja substituir? Logograms - Logo-gramas + Logogramas Special Characters Caracteres especiais + + passwordLength + TamanhoPalavraPasse + + + Characters: %1 + Caracteres: %1 + + + MIXED case + Maiúsculas e minúsculas + + + Excluded characters: "0", "1", "l", "I", "O", "|", "﹒", "B", "8", "G", "6" + Caracteres excluídos: "0", "1", "l", "I", "O", "|", "﹒", "B", "8", "G", "6" + PasswordWidget @@ -6745,7 +7232,7 @@ Tem a certeza de que a deseja substituir? Toggle Password (%1) - Alternar palavra-passe (%1) + Comutar palavra-passe (%1) Generate Password (%1) @@ -6753,7 +7240,7 @@ Tem a certeza de que a deseja substituir? Warning: Caps Lock enabled! - Aviso: Caps Lock ativado + Aviso: tecla de bloqueio de maiúsculas está ativa! Quality: %1 @@ -6781,7 +7268,7 @@ Tem a certeza de que a deseja substituir? Toggle password visibility using Control + H. Open the password generator using Control + G. - Alterne a exibição da palavra-passe com Ctrl + H. Abra o gerador de palavras-passe com Ctrl + G. + Comutar exibição da palavra-passe com Ctrl + H. Abra o gerador de palavras-passe com Ctrl + G. @@ -6799,6 +7286,21 @@ Tem a certeza de que a deseja substituir? Prima &Tab entre os caracteres + + PreviewEntryAttachmentsDialog + + Preview entry attachment + Pré-visualizar anexo + + + No preview available + Pré-visualização indisponível + + + Image format not supported + Formato de imagem não suportado + + QMessageBox @@ -6807,7 +7309,7 @@ Tem a certeza de que a deseja substituir? Delete - Apagar + Eliminar Move @@ -6870,7 +7372,7 @@ Tem a certeza de que a deseja substituir? KeePassXC association failed, try again - Não foi possível associar KeePassXC. Por favor tente novamente + Não foi possível associar o KeePassXC. Por favor tente novamente Encryption key is not recognized @@ -6962,7 +7464,7 @@ Tem a certeza de que a deseja substituir? Cannot generate a password and prompt at the same time. - Não pode utilizar as opções "Gerar palavra-passe" e "Pedir palavra-passe" ao mesmo tempo" + Não pode utilizar as opções "Gerar palavra-passe" e "Pedir palavra-passe" ao mesmo tempo Could not create entry with path %1. @@ -7106,7 +7608,7 @@ Tem a certeza de que a deseja substituir? Could not open attachment file %1. - Não foi possível abrir o anexo %1 + Não foi possível abrir o anexo "%1" Successfully imported attachment %1 as %2 to entry %3. @@ -7180,7 +7682,7 @@ Tem a certeza de que a deseja substituir? Attribute "%1" not found. - Atributo %1 não encontrado + Atributo "%1" não encontrado Entry's "%1" attribute copied to the clipboard! @@ -7477,10 +7979,6 @@ Tem a certeza de que a deseja substituir? Invalid word count %1 Número de palavras inválido: %1 - - The word list is too small (< 1000 items) - A lista de palavras é muito pequena (< 1000 itens) - Title for the entry. Título para a entrada @@ -7625,10 +8123,6 @@ Tem a certeza de que a deseja substituir? Exit interactive mode. Sair do modo interativo - - Format to use when exporting. Available choices are 'xml' or 'csv'. Defaults to 'xml'. - Formato a utilizar para a exportação. As opções possíveis são 'xml' e 'csv'. Por definição, é utilizado o formato 'XML'. - Exports the content of a database to standard output in the specified format. Exporta o conteúdo da base de dados para o formato especificado @@ -7867,7 +8361,7 @@ Comandos disponíveis: Successfully deleted entry %1. - A entrada %1 foi apagada + A entrada %1 foi eliminada Path of the group to remove. @@ -7883,7 +8377,7 @@ Comandos disponíveis: Successfully deleted group %1. - O grupo %1 foi apagado + O grupo %1 foi eliminado Find entries quickly. @@ -8217,18 +8711,6 @@ Kernel: %3 %4 file empty ficheiro vazio - - malformed string - cadeira mal fomada - - - missing closing quote - carácter de fecho em falta - - - %1: (row, col) %2,%3 - %1: (linha, coluna) %2,%3 - AES 256-bit AES 256-bit @@ -8345,7 +8827,7 @@ Kernel: %3 %4 Entry "%1" has %2 reference(s). Do you want to overwrite references with values, skip this entry, or delete anyway? - A entrada "%1" tem %2 referência. Deseja substituir a referência com valores, ignorar ou apagar a entrada?A entrada "%1" tem %2 referências. Deseja substituir as referências com valores, ignorar a entrada ou eliminar?A entrada "%1" tem %2 referências. Deseja substituir as referências com valores, ignorar a entrada ou eliminar? + A entrada "%1" tem %2 referência. Deseja substituir a referência com valores, ignorar ou eliminar?A entrada "%1" tem %2 referências. Deseja substituir as referências com valores, ignorar ou eliminar?A entrada "%1" tem %2 referências. Deseja substituir as referências com valores, ignorar ou eliminar? User name @@ -8545,7 +9027,7 @@ Esta opção está obsoleta, em vez disso use --set-key-file. No Quick Unlock provider is available - Não existe qualquer fornecedor Quick Unlock + Não existe qualquer fornecedor de desbloqueio rápido Failed to init KeePassXC crypto. @@ -8674,13 +9156,89 @@ Esta opção está obsoleta, em vez disso use --set-key-file. Atalhos - Unsupported KDF type, cannot decrypt json file - Tipo de KDF não suportado, não é possível desencriptar o ficheiro json + Unknown passkeys error + Erro desconhecido de chaves-mestras - Unknown passkeys error + Invalid KDF iterations, cannot decrypt json file + Interações KDF inválidas, não é possível decifrar o ficheiro .json + + + Unsupported format, ensure your Bitwarden export is password-protected + Formato não suportado. Verifique se a exportação Bitwarden está protegida por palavra-passe. + + + Only PBKDF and Argon2 are supported, cannot decrypt json file + Apenas existe suporte para PBKDF e Argon2. Não foi possível decifrar o ficheiro json. + + + Reset Shortcuts + Repor atalhos + + + Double click an action to change its shortcut + Dois cliques na ação para alterar o atalho + + + Filter... + Filtro... + + + Shortcut Conflict + Conflito de atalhos + + + Shortcut %1 conflicts with '%2'. Overwrite shortcut? + O atalho %1 está em conflito com '%2'. Substituir atalho? + + + Cannot generate valid passphrases because the wordlist is too short + Não foi possível gerar uma frase-chave válida porque a lista de palavras é pequena + + + Encrypted files are not supported. + Os ficheiros cifrados não não suportados. + + + Proton Pass Import + Importação de Proton Pass + + + Delete plugin data? + Eliminar dados do suplemento? + + + Delete plugin data from Entry(s)? + Eliminar dados do suplemento da entrada?Eliminar dados do suplemento das entradas?Eliminar dados do suplemento das entradas? + + + Passkey + Chave-mestra + + + Format to use when exporting. Available choices are 'xml', 'csv' or 'html'. Defaults to 'xml'. + Formato a utilizar para a exportação. As escolhas possíveis são: 'xml', 'csv' e 'html'. Por omissão, é utilizado o formato 'xml'. + + + start minimized to the system tray + Iniciar minimizado na bandeja do sistema + + + malformed string, possible unescaped delimiter + + missing closing delimiter + + + + %1, row: %2, column: %3 + + + + Tags + Etiquetas + QtIOCompressor @@ -8716,6 +9274,37 @@ Esta opção está obsoleta, em vez disso use --set-key-file. Erro interno zlib: + + RemoteHandler + + Command `%1` did not finish in time. Process was killed. + O comando `%1` não terminou a tempo. O processo foi interrompido. + + + Failed to upload merged database. Command `%1` did not finish in time. Process was killed. + Houve uma falha ao enviar a base de dados combinada. O comando `%1` não foi concluído a tempo. O processo foi interrompido. + + + Invalid download parameters provided. + Foram fornecidos parâmetros de descarregamento inválidos. + + + Command `%1` failed to download database. + O comando `%1` não conseguiu descarregar a base de dados. + + + Invalid database pointer or upload parameters provided. + O ponteiro da base de dados ou os parâmetros de carregamento fornecidos são inválidos. + + + Command `%1` exited with status code: %2 + O comando `%1` foi encerrado com o código de estado: %2 + + + Failed to upload merged database. Command `%1` exited with status code: %2 + Houve uma falha ao carregar a base de dados combinada. O comando `%1` foi encerrado com o código de estado: %2 + + ReportsWidgetBrowserStatistics @@ -8782,6 +9371,10 @@ Esta opção está obsoleta, em vez disso use --set-key-file. Exclude from reports Excluir dos relatórios + + Expire Entry(s)… + Expirar entrada...Expirar entradas...Expirar entradas... + Only show entries that have a URL Mostrar apenas as entradas que tenham um URL @@ -8798,36 +9391,33 @@ Esta opção está obsoleta, em vez disso use --set-key-file. (Expired) (Caducadas) + + Delete plugin data from Entry(s)… + Eliminar dados do suplemento da entrada…Eliminar dados do suplemento das entradas…Eliminar dados do suplemento das entradas… + ReportsWidgetHealthcheck - Hover over reason to show additional details. Double-click entries to edit. - Passe com o rato pelo motivo para obter mais informação. Clique duas vezes na entrada para editar. + Show expired entries + Mostrar entradas caducadas - Bad - Password quality - + (Expired) + (Caducadas) + + + Hover over reason to show additional details. Double-click entries to edit. + Passe com o rato pelo motivo para obter mais informação. Clique duas vezes na entrada para editar. Bad — password must be changed Má - deve alterar a palavra-passe - - Poor - Password quality - - Poor — password should be changed Fraquinha - deve alterar a palavra-passe - - Weak - Password quality - Fraca - Weak — consider changing the password Fraca - considere alterar a palavra-passe @@ -8876,18 +9466,14 @@ Esta opção está obsoleta, em vez disso use --set-key-file. Exclude from reports Excluir dos relatórios - - Show expired entries - Mostrar entradas caducadas + + Expire Entry(s)… + Expirar entrada...Expirar entradas...Expirar entradas... Show entries that have been excluded from reports Mostrar entradas que tenham sido excluídas dos relatórios - - (Expired) - (Caducadas) - ReportsWidgetHibp @@ -8983,6 +9569,10 @@ Esta opção está obsoleta, em vez disso use --set-key-file. Exclude from reports Excluir dos relatórios + + Expire Entry(s)… + Expirar entrada...Expirar entradas...Expirar entradas... + ReportsWidgetPasskeys @@ -9044,11 +9634,11 @@ Esta opção está obsoleta, em vez disso use --set-key-file. Please wait, list of entries with passkeys is being updated… - + Aguarde, a lista de entradas com chaves-mestras está a ser atualizada… No entries with passkeys. - + Não há entradas com chaves-mestras. @@ -9224,12 +9814,20 @@ Esta opção está obsoleta, em vez disso use --set-key-file. No agent running, cannot list identities. O agente não está em execução por isso não é possível listar as identidades. + + Failed to remove all SSH identities from agent. + Falha ao remover todas as identidades SSH do agente. + + + All SSH identities removed from agent. + Todas as identidades SSH foram removidas do agente. + SearchHelpWidget Search Help - Pesquisar na ajuda + Ajuda sobre pesquisas Search terms are as follows: [modifiers][field:]["]term["] @@ -9288,7 +9886,7 @@ Esta opção está obsoleta, em vez disso use --set-key-file. Search Help - Pesquisar na ajuda + Ajuda sobre pesquisas Save Search @@ -9509,29 +10107,6 @@ Esta opção está obsoleta, em vez disso use --set-key-file. Exportar para %1 - - ShortcutSettingsWidget - - Double click an action to change its shortcut - Dois cliques na ação para alterar o atalho - - - Shortcut Conflict - Conflito de atalhos - - - Filter... - Filtro... - - - Shortcut %1 conflicts with '%2'. Overwrite shortcut? - O atalho %1 está em conflito com '%2'. Substituir atalho? - - - Reset Shortcuts - Repor atalhos - - TagModel @@ -9679,7 +10254,7 @@ Example: JBSWY3DPEHPK3PXP Are you sure you want to delete TOTP settings for this entry? - Tem a certeza de que deseja remover as definições TOTP desta entrada? + Tem a certeza de que deseja eliminar as definições TOTP desta entrada? @@ -9819,14 +10394,18 @@ Example: JBSWY3DPEHPK3PXP No hardware keys detected Não foram detetadas chaves de hardware - - <p>If you own a <a href="https://www.yubico.com/">YubiKey</a> or <a href="https://onlykey.io">OnlyKey</a>, you can use it for additional security.</p><p>The key requires one of its slots to be programmed as <a href="https://docs.yubico.com/yesdk/users-manual/application-otp/challenge-response.html">HMAC-SHA1 Challenge-Response</a>.</p> - <p>Se tiver uma <a href="https://www.yubico.com/">YubiKey</a> ou <a href="https://onlykey.io">Only Key</a>, pode utilizá-la para mais segurança.</p><p>A chave requer que uma das suas ranhuras seja programada como <a href="https://docs.yubico.com/yesdk/users-manual/application-otp/challenge-response.html">HMAC-SHA1 Challenge-Response</a>.</p> - Refresh hardware keys Recarregar chaves de hardware + + <p>If you own a <a href="https://www.yubico.com/">YubiKey</a> or <a href="https://onlykey.io">OnlyKey</a>, you can use it for additional security.</p><p>The key requires one of its slots to be programmed with <a href="https://keepassxc.org/docs/#faq-yubikey-howto">Challenge-Response</a>.</p> + <p>Se tiver uma <a href="https://www.yubico.com/">YubiKey</a> ou <a href="https://onlykey.io">Only Key</a>, pode utilizar para manter uma segurança adicional.</p><p>A chave requer que uma das suas ranhuras seja programada como <a href="https://keepassxc.org/docs/#faq-yubikey-howto">Challenge-Response</a>.</p> + + + Hardware keys found, but no slots are configured + A chave física foi encontrada mas não está configurada. + YubiKeyInterfacePCSC diff --git a/share/translations/keepassxc_ro.ts b/share/translations/keepassxc_ro.ts index 5c50fd22c..b9744cb6e 100644 --- a/share/translations/keepassxc_ro.ts +++ b/share/translations/keepassxc_ro.ts @@ -58,7 +58,8 @@ <html><head/><body><p><span style=" font-weight:600;">%1 </span>is requesting access to the following entries:</p></body></html> - + <html><head/><body><p><span style=" font-weight:600;">%1 </span>solicită acces la următoarele intrări: +</p></body></html> Name @@ -78,34 +79,34 @@ Details - - - - Remember - - - - Allow Selected - + Detalii Your decision will be remembered for the duration while both the requesting client AND KeePassXC are running. - + Decizia dvs. va fi reținută pe toată durata în care rulează atât clientul solicitant cât și KeePassXC. + + + Remember + Reține + + + Allow Selected + Permiteți selectate Deny All && Future - + Refuză toate && în viitor Allow All && &Future - + Permite toate && &în viitor AccessControlDialog::DenyButton Deny for this program - + Refuză pentru acest program @@ -122,6 +123,10 @@ Use OpenSSH + + Use both agents + + SSH_AUTH_SOCK override @@ -150,10 +155,6 @@ SSH Agent connection is working! - - Use both agents - - ApplicationSettingsWidget @@ -169,6 +170,10 @@ Security Securitate + + This setting cannot be enabled when minimize on unlock is enabled. + Această setare nu poate fi activată atunci când este activată funcția de minimizare la deblocare. + Access error for config file %1 Eroare de acces pentru fisier de configurare %1 @@ -199,34 +204,62 @@ Monochrome (light) - + Monochrome (luminos) Monochrome (dark) - + Monochrome (întunecat) Colorful - + Colorată You must restart the application to set the new language. Would you like to restart now? - - - - Reset Settings? - Resetare Setări? - - - Are you sure you want to reset all general and security settings to default? - Sigur resetați în mod implicit toate setările generale și de securitate ? + Trebuie să reporniți aplicația pentru a seta noua limbă. Doriți să reporniți acum? Select backup storage directory + Selectați directorul de stocare de backup + + + Confirm Reset - This setting cannot be enabled when minimize on unlock is enabled. + Are you sure you want to reset all settings to default? + + + + Import KeePassXC Settings + + + + Failed to import settings from %1, not a valid settings file. + + + + Export KeePassXC Settings + + + + Small + + + + Normal + + + + Medium + + + + Large + + + + Custom @@ -246,7 +279,7 @@ Automatically launch KeePassXC at system startup - + Lansarea automată a KeePassXC la pornirea sistemului Minimize window at application startup @@ -260,6 +293,10 @@ Remember previously used databases Retine bazele de date utilizate anterior + + recent files + fișiere recente + Load previously open databases on startup la pornirea incărcarea bazelor de date deschise anterior @@ -276,25 +313,6 @@ Include beta releases when checking for updates Includere versiuni beta la verificarea actualizărilor - - On database unlock, show entries that - - - - have expired - On database unlock, show entries that... - - - - days - On database unlock, show entries that will expire within %1 days - - - - will expire within - On database unlock, show entries that... - - File Management Gestionare fișiere @@ -305,11 +323,11 @@ Automatically save when locking database - + Salvare automată la blocarea bazei de date Automatically save non-data changes when locking database - + Salvare automată a modificărilor fără date atunci când se blochează baza de date Automatically reload the database when modified externally @@ -319,33 +337,21 @@ Backup database file before saving Fă copie de rezervă fișierului bazei de date înainte de salvare - - Backup destination - - - - Specifies the database backup file location. Occurrences of "{DB_FILENAME}" are replaced with the filename of the saved database without extension. {TIME:<format>} is replaced with the backup time, see https://doc.qt.io/qt-5/qdatetime.html#toString. <format> defaults to format string "dd_MM_yyyy_hh-mm-ss". - - {DB_FILENAME}.old.kdbx - - Choose... - - Use alternative saving method (may solve problems with Dropbox, Google Drive, GVFS, etc.) Temporary file moved into place - + Fișierul temporar a fost mutat la locul său Directly write to database file (dangerous) - + Scrierea directă în fișierul bazei de date (periculos) Entry Management @@ -386,7 +392,7 @@ User Interface - + Interfața cu utilizatorul Toolbar button style @@ -410,11 +416,15 @@ Toolbar button style: - + Stilul butonului din bara de instrumente: + + + Show passwords in color + Afișați parolele în culori Use monospaced font for notes - + Utilizați un font monospațiat pentru note Minimize instead of app exit @@ -426,11 +436,11 @@ Tray icon type - + Tipul de pictogramă din tavă Tray icon type: - + Tipul de pictogramă din tavă: Hide window to system tray when minimized @@ -438,43 +448,43 @@ Reset settings to default… - + Resetați setările la valorile implicite... Auto-Type - Auto tiparire + Auto-tastare Use entry title to match windows for global Auto-Type - Utilizarea titlului inregistrarii pentru a se potrivi cu ferestrele pentru auto-tiparire globala + Utilizează titlul înregistrării pentru a se potrivi cu ferestrele pentru auto-tastare globală Use entry URL to match windows for global Auto-Type - Utilizați URL-ul din inregistrare pentru a se potrivi Windows pentru autotiparire globala + Utilizează URL-ul din înregistrare pentru a se potrivi cu ferestrele pentru auto-tastare globală Always ask before performing Auto-Type - Întrebați întotdeauna înainte de a efectua auto-tiparire + Întreabă întotdeauna înainte de a efectua auto-tastare Hide expired entries from Auto-Type - + Ascunde din auto-tastare înregistrările expirate Re-lock previously locked database after performing Auto-Type - Re-Lock bazei de date blocate anterior după efectuarea auto-Type + Încuie din nou baza de dată blocată anterior după efectuarea auto-tastării Auto-Type start delay: - + Întârziere la pornire pentru auto-tastare: Global Auto-Type shortcut: - + Scurtătură globală pentru auto-tastare: Auto-type start delay milliseconds - Auto-tip de pornire întârziere milisecunde + Milisecunde de întârziere la pornire pentru auto-tastare ms @@ -483,26 +493,83 @@ Auto-Type typing delay: - + Întârziere la tastare pentru auto-tastare: Global auto-type shortcut - Comandă rapidă de tip auto global + Scurtătură globală pentru auto-tastare Auto-type character typing delay milliseconds - Tipul de auto-tastare întârziere milisecunde + Milisecunde de întârziere la auto-tastare de caracter Remember last typed entry for: + Țineți minte ultima intrare introdusă pentru: + + + On database unlock, show entries that will expire within - recent files + On database unlock, show entries that will expire within - Show passwords in color + days + number of days warning for password expiration + zile + + + Destination format: + + + + <html><head/><body><p><span style=" font-weight:600;">{DB_FILENAME}</span> is replaced with the filename of the saved database without extension</p><p><span style=" font-weight:600;">{TIME:&lt;format&gt;}</span> is replaced with the specified time format (default: dd_MM_yyyy_hh-mm-ss)</p><p>See the User Guide for more details</p></body></html> + + + + Choose folder... + + + + Show confirmation before moving entries to recycle bin + + + + Copy data on double clicking field in entry view + + + + Show toolbar + + + + Show the menu bar by pressing the Alt key + + + + Show menubar + + + + Import settings… + + + + Export settings… + + + + Open browser on double clicking URL field in entry view + + + + Font size: + + + + Font size selection @@ -548,7 +615,7 @@ Enable database quick unlock (Touch ID / Windows Hello) - + Activați deblocarea rapidă a bazei de date (Touch ID / Windows Hello) Lock databases when session is locked or lid is closed @@ -558,34 +625,18 @@ Lock databases after minimizing the window Blocarea bazelor de date după Minimizarea ferestrei - - Require password repeat when it is visible - - Hide passwords when editing them - + Ascundeți parolele atunci când le editați Use placeholder for empty password fields - + Utilizați un marcaj pentru câmpurile de parolă goale Hide passwords in the entry preview panel Ascunderea parolelor în panoul de previzualizare inregistrarii - - Hide entry notes by default - Ascundere implicită notei inregistrarii - - - Move entries to recycle bin without confirmation - - - - Enable double click to copy the username/password entry columns - - Privacy Confidențialitate @@ -596,6 +647,18 @@ Hide TOTP in the entry preview panel + Ascundeți TOTP în panoul de previzualizare a intrării + + + Lock databases when switching user + + + + Lock Options + + + + Hide notes in the entry preview panel @@ -603,11 +666,11 @@ AutoType The requested Auto-Type sequence cannot be used due to an error: - + Secvența de auto-tastare cerută nu poate fi folosită din cauza unei erori: Auto-Type Error - + Eroare de auto-tastare Permission Required @@ -619,11 +682,11 @@ KeePassXC requires the Accessibility and Screen Recorder permission in order to perform global Auto-Type. Screen Recording is necessary to use the window title to find entries. If you already granted permission, you may have to restart KeePassXC. - + KeePassXC necesită permisiunile de accesibilitate și înregistrare de ecran pentru a efectua auto-tastare la nivel global. Înregistrarea ecranului este necesară pentru a folosi titlul ferestrelor pentru a găsi înregistrări. Dacă ați acordat deja permisiunea, poate fi nevoie să reporniți KeePassXC. Invalid entry provided - + Intrare invalidă furnizată Bracket imbalance detected, found extra { or } @@ -642,26 +705,13 @@ - Invalid conversion type: %1 - - - - Invalid conversion syntax: %1 - - - - Invalid regular expression syntax %1 -%2 + Entry does not have attribute for PICKCHARS: %1 Invalid placeholder: %1 - - Entry does not have attribute for PICKCHARS: %1 - - AutoTypeAssociationsModel @@ -703,13 +753,9 @@ AutoTypePlatformX11 - - Trying to send invalid keysym. - - Sequence aborted: Caps Lock is on - + Secvență anulată: Caps Lock este activat Sequence aborted: Modifier keys held by user @@ -719,16 +765,20 @@ Unable to get valid keycode for key: + + Trying to send invalid keyboard symbol. + + AutoTypeSelectDialog Auto-Type - KeePassXC - Auto-tip-KeePassXC + Auto-tastare - KeePassXC Double click a row to perform Auto-Type or find an entry using the search: - + Dați dublu clic pe un rând pentru a efectua auto-tastare sau pentru a găsi o înregistrare folosind căutarea: <p>You can use advanced search queries to find any entry in your open databases. The following shortcuts are useful:<br/> @@ -737,15 +787,20 @@ Ctrl+1 - Type username<br/> Ctrl+2 - Type password<br/> Ctrl+3 - Type TOTP<br/> Ctrl+4 - Use Virtual Keyboard (Windows Only)</p> - + Puteți utiliza interogări de căutare avansate pentru a găsi orice intrare în bazele de date deschise. Următoarele scurtături sunt utile: +Ctrl+F - Comutarea căutării în baza de date +Ctrl+1 - Introduceți numele de utilizator +Ctrl+2 - Introduceți parola +Ctrl+3 - Introduceți TOTP +Ctrl+4 - Folosiți tastatura virtuală (numai pentru Windows) Search all open databases - + Căutați în toate bazele de date deschise Search… - + Căutare... Type Sequence @@ -769,15 +824,15 @@ Ctrl+4 - Use Virtual Keyboard (Windows Only)</p> Copy Username - + Copiați numele de utilizator Copy Password - + Copiați parola Copy TOTP - + Copiați TOTP Use Virtual Keyboard @@ -788,43 +843,43 @@ Ctrl+4 - Use Virtual Keyboard (Windows Only)</p> BrowserAccessControlDialog KeePassXC - Browser Access Request - + KeePassXC - Solicitare de acces la browser %1 is requesting access to the following entries: - + %1 solicită acces la următoarele intrări: Remember access to checked entries - + Rețineți accesul la intrările verificate Remember - + Reține Allow access to entries - + Permiteți accesul la intrări Allow Selected - + Permiteți selectate Deny All - + Refuză toate Disable for this site + Dezactivați pentru acest site + + + Undo BrowserEntrySaveDialog - - KeePassXC-Browser Save Entry - KeePassXC-browser-ul salvare inregistrarii - Ok Ok @@ -839,13 +894,75 @@ Please select the correct database for saving credentials. Aveți mai multe baze de date deschise. Selectați baza de date corectă pentru salvarea acreditărilor. + + KeePassXC - Select Database + KeePassXC - Selectați baza de date + + + + BrowserPasskeysConfirmationDialog + + Cancel + Anulare + + + Update + + + + Authenticate + + + + Register new + Înregistrare nouă + + + Register + + + + Timeout in <b>%n</b> seconds... + + + + Relying Party: %1 + + + + Username: %1 + + + + KeePassXC - Passkey credentials + KeePassXC - Cheie de acces pentru acreditări + + + Add to existing entry + + + + Existing passkey found. +Do you want to register a new passkey for: + S-a găsit o cheie de acces existentă. +Doriți să înregistrați o nouă cheie de acces pentru: + + + + Select the existing passkey and press Update to replace it. + Selectați cheia de acces existentă și apăsați Actualizare pentru a o înlocui. + + + Authenticate passkey credentials for: + Autentificați acreditările cu cheie de acces pentru: + + + Do you want to register a passkey for: + Doriți să înregistrați o cheie de acces pentru: + BrowserService - - KeePassXC: Create a new group - KeePassXC: crearea unui grup nou - A request for creating a new group "%1" has been received. Do you want to create this group? @@ -853,10 +970,6 @@ Do you want to create this group? S-a primit o solicitare de creare a unui grup nou "%1". Doriți să creați acest grup? - - KeePassXC: New key association request - KeePassXC: noua cerere de asociere cheie - You have received an association request for the following database: %1 @@ -873,79 +986,75 @@ chrome-laptop. Save and allow access Salvează și permite acces - - KeePassXC: Overwrite existing key? - KeePassXC: Suprascriere cheie existentă? - A shared encryption key with the name "%1" already exists. Do you want to overwrite it? Există deja o cheie de criptare partajată cu numele "%1" . Doriți să o suprascrieți? - - KeePassXC: Update Entry - KeePassXC: actualizare intrare - Do you want to update the information in %1 - %2? Actualizați informațiile în %1 - %2 ? - - KeePassXC: Delete entry - - A request for deleting entry "%1" has been received. Do you want to delete the entry? + A fost primită o cerere de ștergere a intrării "%1". +Doriți să ștergeți această intrare? + + + %1 (Passkey) + %1 (Cheie de acces) + + + KeePassXC - Create a new group + KeePassXC - Creare grup nou + + + Disable + Dezactivează + + + KeePassXC - Overwrite existing key? - Converting attributes to custom data… - Conversia atributelor in date particularizate... + KeePassXC - Update Entry + - Abort - Anulează + KeePassXC - Delete entry + KeePassXC - Ștergeți intrarea - KeePassXC: Converted KeePassHTTP attributes - KeePassXC: conversia atributelor KeePassHTTP + KeePassXC - New key association request + KeePassXC - Solicitare nouă de asociere chei - Successfully converted attributes from %1 entry(s). -Moved %2 keys to custom data. - Atributele convertite cu succes din %1 intrare (i). -S-au mutat %2 chei la date particularizate. - - - Successfully moved %n keys to custom data. - S-au mutat cu succes% n chei la date particularizate.S-au mutat cu succes% n chei la date particularizate.S-au mutat cu succes %n chei la date particularizate. + Passkey + Cheie de acces - KeePassXC: No entry with KeePassHTTP attributes found! - KeePassXC: n-a fost găsita nici o intrare cu KeePassHTTP atribute ! + KeePassXC - Passkey credentials + KeePassXC - Cheie de acces pentru acreditări - The active database does not contain an entry with KeePassHTTP attributes. - Baza de date activă nu conține nici o intrare cu atributele KeePassHTTP. + Register a new passkey to this entry: + Înregistrați o nouă cheie de acces pentru această intrare: - Don't show this warning again - Nu mai afișa acest avertisment + KeePassXC - Update passkey + KeePassXC - Actualizare cheie de acces - KeePassXC: Legacy browser integration settings detected - KeePassXC: Au fost detectate setările moștenite de integrare a browserului + Entry already has a passkey. +Do you want to overwrite the passkey in %1 - %2? + - Your KeePassXC-Browser settings need to be moved into the database settings. -This is necessary to maintain your current browser connections. -Would you like to migrate your existing settings now? - Setările KeePassXC-browser trebuie mutate în setările bazei de date. -Acest lucru este necesar pentru a menține conexiunile browser-ului curent. -Migrați acum setările existente? + Register + @@ -966,10 +1075,6 @@ Migrați acum setările existente? General General - - Browsers installed as snaps are currently not supported. - Browserele instalate ca snaps nu sunt acceptate momentan. - Enable integration for these browsers: Activați integrarea pentru aceste browsere: @@ -1005,11 +1110,11 @@ Migrați acum setările existente? Show a notification when credentials are requested Credentials mean login data requested via browser extension - + Afișează o notificare atunci când sunt solicitate acreditări Request to unlock the database if it is locked - + Cerere de deblocare a bazei de date în cazul în care aceasta este blocată Only entries with the same scheme (http://, https://, …) are returned. @@ -1042,7 +1147,7 @@ Migrați acum setările existente? Search in all opened databases for matching credentials Credentials mean login data requested via browser extension - + Căutați în toate bazele de date deschise pentru acreditările corespunzătoare Advanced @@ -1107,7 +1212,7 @@ Migrați acum setările existente? Browse… Button for opening file dialog - + Răsfoiți... Use a custom browser configuration location: @@ -1141,18 +1246,6 @@ Migrați acum setările existente? Custom extension ID - - Due to Snap sandboxing, you must run a script to enable browser integration.<br />You can obtain this script from %1 - Datorită snap sandboxing, trebuie să executați un script pentru a activa integrarea browser-ului.<br>Puteți obține acest script de la % 1 - - - KeePassXC-Browser is needed for the browser integration to work. <br />Download it for %1 and %2 and %3. %4 - - - - Please see special instructions for browser extension use below - Vă rugăm să consultați instrucțiunile speciale pentru utilizarea extensiei browserului de mai jos - Executable Files Fișiere executabile @@ -1169,6 +1262,14 @@ Migrați acum setările existente? Select native messaging host folder location + + Allow keepassxc-proxy to list all entries with their title, URL and UUID in connected databases. + + + + Allow limited access to all entries in connected databases (ignores site access restrictions) + + <b>Warning:</b> Only adjust these settings if necessary. @@ -1185,12 +1286,28 @@ Migrați acum setările existente? <b>Error:</b> The installed proxy executable is missing from the expected location: %1<br/>Please set a custom proxy location in the advanced settings or reinstall the application. + + Allows using insecure http://localhost with passkeys for testing purposes. + + + + Allow using localhost with passkeys + + + + KeePassXC-Browser is needed for the browser integration to work. <br />Download it for %1 and %2 and %3. + + + + Browsers installed using Snap or Flatpak are not supported with exception to Firefox installed using Snap. + + CloneDialog Clone Entry Options - + Opțiuni de intrare pentru clonare Append ' - Clone' to title @@ -1207,14 +1324,6 @@ Migrați acum setările existente? CsvImportWidget - - Import CSV fields - Importă câmpuri CSV - - - filename - nume fișier - size, rows, columns dimensiune, rânduri, coloane @@ -1323,50 +1432,42 @@ Migrați acum setările existente? Column %1 - - Imported from CSV file - Importat din fișier CSV - - - Original data: - Datele originale: - - - Error(s) detected in CSV file! - Eroare (i) detectată în fișierul CSV! - [%n more message(s) skipped] [% n mai mult mesaj (e) ignorate][% n mai mult mesaj (e) ignorate][%n mai mult mesaj (e) ignorate] - Error - Eroare + Failed to parse CSV file: %1 + - CSV import: writer has errors: -%1 - Import CSV: scriitor are erori: -%1 + Imported from CSV file: %1 + Importat dintr-un fișier CSV: %1 + + + No Title Selected + + + + No title column was selected, entries will be hard to tell apart. +Are you sure you want to import? + + + + Tags + Etichete CsvParserModel - - %1, %2, %3 - file info: bytes, rows, columns - %1, %2, %3 - - - %n byte(s) - % n byte (e)% n byte (e)%n byte (e) - %n row(s) + CSV row count % n rând (e)% n rând (e)%n rând (uri) %n column(s) + CSV column count % n coloană (e)% n coloană (e)%n coloană (e) @@ -1395,11 +1496,11 @@ Migrați acum setările existente? Database save is already in progress. - + Salvarea bazei de date este deja în curs de desfășurare. Could not save, database has not been initialized! - + Nu s-a putut salva, baza de date nu a fost inițializată! Database file has unmerged changes. @@ -1413,12 +1514,20 @@ Baza de date de rezervă localizată la %2 Key not transformed. This is a bug, please report it to the developers. - + Cheia nu a fost transformată. Aceasta este o eroare, vă rugăm să o raportați dezvoltatorilor. Recycle Bin Coș de gunoi + + Database file read error. + + + + No file path was provided. + + DatabaseOpenDialog @@ -1441,33 +1550,13 @@ Baza de date de rezervă localizată la %2 Password field Câmp parola - - Enter Additional Credentials (if any): - Introduceți acreditări suplimentare (dacă există): - - - Key File: - Fișier cheie: - - - Key file help - Ajutor de fișiere cheie - Hardware key slot selection Selectarea sloturilor pentru cheie hardware - - Hardware Key: - Cheie hardware: - - - Hardware key help - Ajutor cheie hardware - Key file to unlock the database - + Fișier cheie pentru deblocarea bazei de date Browse for key file @@ -1475,19 +1564,11 @@ Baza de date de rezervă localizată la %2 Browse… - - - - Refresh hardware tokens - Actualizați jetoane hardware - - - Refresh - Actualizează + Răsfoiți... Unlock Database - + Deblocare bază de date Cancel @@ -1495,7 +1576,7 @@ Baza de date de rezervă localizată la %2 Unlock - + Deblocare Please present or touch your YubiKey to continue… @@ -1503,7 +1584,7 @@ Baza de date de rezervă localizată la %2 Database Version Mismatch - + Nepotrivire de versiune a bazei de date The database you are trying to open was most likely @@ -1513,15 +1594,21 @@ You can try to open it anyway, but it may be incomplete and saving any changes may incur data loss. We recommend you update your KeePassXC installation. - + Baza de date pe care încercați să o deschideți a fost cel mai probabil +creată de o versiune mai nouă a KeePassXC. + +Puteți încerca să o deschideți oricum, dar este posibil să fie incompletă +iar salvarea oricăror modificări poate atrage pierderi de date. + +Vă recomandăm să vă actualizați instalarea KeePassXC. Open database anyway - + Deschideți oricum baza de date Database unlock canceled. - + Deblocarea bazei de date a fost anulată. Unlock failed and no password given @@ -1541,10 +1628,6 @@ Pentru a preveni apariția acestei erori, trebuie să accesați „Setări baza Retry with empty password Încercați din nou cu parola goală - - Failed to authenticate with Touch ID - - Failed to open key file: %1 Nu a putut fi deschis fișierul cheii: %1 @@ -1577,43 +1660,68 @@ Pentru a preveni apariția acestei erori, trebuie să accesați „Setări baza Cannot use database file as key file Nu se poate utiliza fișierul bazei de date ca fișier cheie - - You cannot use your database file as a key file. -If you do not have a key file, please leave the field empty. - Nu puteți utiliza fișierul dvs. de bază de date ca fișier cheie. -Dacă nu aveți un fișier cheie, lăsați câmpul gol. - - - Detecting hardware keys… - - - - No hardware keys detected - - - - Select hardware key… - - - - <p>In addition to a password, you can use a secret file to enhance the security of your database. This file can be generated in your database's security settings.</p><p>This is <strong>not</strong> your *.kdbx database file!<br>If you do not have a key file, leave this field empty.</p><p>Click for more information…</p> - - - - <p>You can use a hardware security key such as a <strong>YubiKey</strong> or <strong>OnlyKey</strong> with slots configured for HMAC-SHA1.</p> -<p>Click for more information…</p> - - authenticate to access the database + autentificare pentru a accesa baza de date + + + Failed to authenticate with Quick Unlock: %1 - Failed to authenticate with Windows Hello: %1 + Select Key File: - Windows Hello setup was canceled or failed. Quick unlock has not been enabled. + <p>In addition to a password, you can use a secret file to enhance the security of your database. This file can be generated in your database's security settings.</p><p>This is <strong>not</strong> your *.kdbx database file!</p> + <p>În plus față de o parolă, puteți utiliza un fișier secret pentru a spori securitatea bazei de date. Acest fișier poate fi generat în setările de securitate ale bazei dvs. de date.</p><p>Acesta<strong> nu este</strong> fișierul dvs. de bază de date *.kdbx!</p> + + + Use hardware key [Serial: %1] + + + + Use hardware key + + + + Your database file is NOT a key file! +If you don't have a key file or don't know what that is, you don't have to select one. + Fișierul bazei dvs. de date NU este un fișier cheie! +Dacă nu aveți un fișier cheie sau nu știți ce este acesta, nu trebuie să selectați unul. + + + KeePassXC database file selected + Fișier bază de date KeePassXC selectat + + + The file you selected looks like a database file. +A database file is NOT a key file! + +Are you sure you want to continue with this file?. + Fișierul pe care l-ați selectat arată ca un fișier de bază de date. +Un fișier de bază de date NU este un fișier cheie! + +Sunteți sigur că doriți să continuați cu acest fișier?. + + + No hardware keys found. + + + + Refresh Hardware Keys + Reîmprospătarea tastelor hardware + + + Click to add a key file. + + + + <a href="#" style="text-decoration: underline">I have a key file</a> + + + + Hardware keys found, but no slots are configured. @@ -1626,10 +1734,6 @@ Dacă nu aveți un fișier cheie, lăsați câmpul gol. DatabaseSettingsDialog - - Advanced Settings - Setări avansate - General General @@ -1640,7 +1744,7 @@ Dacă nu aveți un fișier cheie, lăsați câmpul gol. Database Credentials - + Credențiale pentru baza de date Encryption Settings @@ -1654,6 +1758,22 @@ Dacă nu aveți un fișier cheie, lăsați câmpul gol. Maintenance + + KeeShare + De la KeeShare + + + Secret Service Integration + Integrarea serviciilor secrete + + + Remote Sync + + + + Database Settings: %1 + + DatabaseSettingsWidgetBrowser @@ -1661,18 +1781,6 @@ Dacă nu aveți un fișier cheie, lăsați câmpul gol. KeePassXC-Browser settings Setări KeePassXC-Browser - - Convert KeePassHTTP data - - - - Convert legacy KeePassHTTP attributes to KeePassXC-Browser compatible custom data - - - - Refresh database root group ID - - Disconnect all browsers Deconectează toate navigatoarele web @@ -1681,6 +1789,10 @@ Dacă nu aveți un fișier cheie, lăsați câmpul gol. Forget all site-specific settings on entries Uita toate setările specifice site-ului pe intrările + + Refresh database root group ID + Împrospătați ID-ul grupului rădăcină al bazei de date + Stored keys Taste memorate @@ -1729,18 +1841,10 @@ This may prevent connection to the browser plugin. Chiar doriți să deconectați toate browserele? Acest lucru poate împiedica conectarea la plugin-ul browser-ului. - - KeePassXC: No keys found - KeePassXC: nu s-au găsit chei - No shared encryption keys found in KeePassXC settings. Nu sunt găsite chei de criptare partajate în setările KeePassXC. - - KeePassXC: Removed keys from database - KeePassXC: cheile sterse din baza de date - Successfully removed %n encryption key(s) from KeePassXC settings. S-a eliminat cu succes% n cheie de criptare din setările KeePassXC.S-a eliminat cu succes% n cheie de criptare din setările KeePassXC.S-a eliminat cu succes %n chei de criptare din setările KeePassXC. @@ -1759,38 +1863,42 @@ Permisiunile de accesare a intrărilor vor fi revocate. Abort Anulează - - KeePassXC: Removed permissions - KeePassXC: permisiuni eliminate - Successfully removed permissions from %n entry(s). Permisiuni eliminate cu succes de la% n intrare (e).Permisiuni eliminate cu succes de la% n intrare (e).Permisiuni eliminate cu succes pentru %n intrare(i). - - KeePassXC: No entry with permissions found! - KeePassXC: nici o intrare cu permisiuni găsit! - The active database does not contain an entry with permissions. Baza de date activă nu conține o intrare cu permisiuni. - - Move KeePassHTTP attributes to custom data - Mutarea atributelor KeePassHTTP la date particularizate - - - Do you really want to convert all legacy browser integration data to the latest standard? -This is necessary to maintain compatibility with the browser plugin. - - Refresh database ID - + Actualizați ID-ul bazei de date Do you really want refresh the database ID? This is only necessary if your database is a copy of another and the browser extension cannot connect. + Chiar doriți să reîmprospătați ID-ul bazei de date? +Acest lucru este necesar doar dacă baza de date este o copie a alteia și extensia browserului nu se poate conecta. + + + Convert legacy KeePassHTTP attributes to KeePassXC-Browser compatible custom data + + + + No keys found + + + + Removed keys from database + Chei eliminate din baza de date + + + Removed permissions + + + + No entry with permissions found! @@ -1830,6 +1938,18 @@ Sigur continuați fără parolă? Failed to change database credentials + Nu s-a reușit modificarea credențialelor bazei de date + + + Weak password + + + + This is a weak password! For better protection of your secrets, you should choose a stronger password. + + + + The provided password does not meet the minimum quality requirement. @@ -1839,14 +1959,6 @@ Sigur continuați fără parolă? Decryption Time: Timp de decriptare: - - Change existing decryption time - Modificați timpul de decriptare existent - - - Change - Schimba - Decryption time in seconds Timpul de decriptare în secunde @@ -1869,7 +1981,7 @@ Sigur continuați fără parolă? Unless you need to open your database with other programs, always use the latest format. - + Cu excepția cazului în care aveți nevoie să vă deschideți baza de date cu alte programe, utilizați întotdeauna cel mai recent format. Encryption Algorithm: @@ -1927,11 +2039,6 @@ Sigur continuați fără parolă? KDBX 3 - - unchanged - Database decryption time is unchanged - Neschimbat - Number of rounds too high Key transformation rounds @@ -1941,7 +2048,9 @@ Sigur continuați fără parolă? You are using a very high number of key transform rounds with Argon2. If you keep this number, your database may take hours, days, or even longer to open. - + Folosiți un număr foarte mare de runde de transformare a cheilor cu Argon2. + +Dacă păstrați acest număr, este posibil ca deschiderea bazei dvs. de date să dureze ore, zile sau chiar mai mult. Understood, keep number @@ -1980,6 +2089,18 @@ If you keep this number, your database will not be protected from brute force at Threads for parallel execution (KDF settings) filet (e)filet (e)thread(s) + + Encryption Settings: + + + + Basic + + + + Advanced + Avansat + DatabaseSettingsWidgetFdoSecrets @@ -1989,7 +2110,7 @@ If you keep this number, your database will not be protected from brute force at Don't expose this database - + Nu expuneți această bază de date Expose entries under this group: @@ -2004,7 +2125,7 @@ If you keep this number, your database will not be protected from brute force at DatabaseSettingsWidgetGeneral Database Metadata - + Metadatele bazei de date Database name: @@ -2099,6 +2220,73 @@ add up to the specified amount at most. instead of deleting them from the database. Entries deleted from the recycle bin are removed from the database. + Mutarea intrărilor într-un grup de coș de gunoi +în loc să le ștergeți din baza de date. +Înregistrările șterse din coșul de gunoi sunt +eliminate din baza de date. + + + Autosave delay since last change + + + + Autosave delay + + + + Autosave delay since last change in minutes + + + + min + Min + + + Autosave delay since last change checkbox + + + + Public Database Metadata + + + + Warning: the following settings are not encrypted. + + + + Display name: + + + + Publically visible display name used on the unlock dialog + + + + Database public display name + + + + Display color: + + + + Publically visible color used on the unlock dialog + + + + Database public display color chooser + + + + Clear + Golește + + + Display icon: + + + + Select Database Icon @@ -2142,11 +2330,11 @@ removed from the database. Delete selected icon(s) - + Ștergeți pictogramele selectate Delete all custom icons not in use by any entry or group - + Ștergeți toate pictogramele personalizate care nu sunt utilizate de nicio intrare sau grup Purge unused icons @@ -2158,7 +2346,7 @@ removed from the database. At least one of the selected icons is currently in use by at least one entry or group. The icons of all affected entries and groups will be replaced by the default icon. Are you sure you want to delete icons that are currently in use? - + Cel puțin una dintre pictogramele selectate este utilizată în prezent de cel puțin o intrare sau un grup. Pictogramele tuturor intrărilor și grupurilor afectate vor fi înlocuite cu pictograma implicită. Sunteți sigur că doriți să ștergeți pictogramele care sunt utilizate în prezent? Custom Icons Are In Use @@ -2196,6 +2384,129 @@ removed from the database. Câmpul descrierii bazei de date + + DatabaseSettingsWidgetRemote + + Sync Commands + + + + Remove + Înlătură + + + Command Settings + + + + Name + Nume + + + Save + Salvează + + + Download + + + + Command: + + + + Download command field + + + + e.g.: "sftp user@hostname" or "scp user@hostname:DatabaseOnRemote.kdbx {TEMP_DATABASE}" + + + + Input: + + + + Download input field + + + + Upload + + + + Upload command field + + + + e.g.: "sftp user@hostname" or "scp {TEMP_DATABASE} user@hostname:DatabaseOnRemote.kdbx" + + + + Upload input field + + + + Name cannot be empty. + + + + Test + + + + Download command cannot be empty. + + + + Download failed with error: %1 + + + + Download finished, but file %1 could not be found. + + + + Download successful. + + + + Save Remote Settings + + + + You have unsaved changes. Do you want to save them? + + + + e.g.: +get DatabaseOnRemote.kdbx {TEMP_DATABASE} +exit +--- +{TEMP_DATABASE} is used as placeholder to store the database in a temporary location +The command has to exit. In case of `sftp` as last command `exit` has to be sent + + + + + e.g.: +put {TEMP_DATABASE} DatabaseOnRemote.kdbx +exit +--- +{TEMP_DATABASE} is used as placeholder to store the database in a temporary location +The command has to exit. In case of `sftp` as last command `exit` has to be sent + + + + + Timeout: + + + + seconds + secunde + + DatabaseTabWidget @@ -2228,26 +2539,10 @@ Acest lucru este cu siguranta un bug, vă rugăm să raporteze la dezvoltatori.< CSV file Fișier CSV - - Select CSV file - Selectați fișierul CSV - Merge database Îmbină baza de date - - KeePass 1 database - Bază de date KeePass 1 - - - Open KeePass 1 database - Deschide bază de date KeePass 1 - - - Open OPVault - - Export database to CSV file Exportă baza de date în fișier CSV @@ -2260,28 +2555,6 @@ Acest lucru este cu siguranta un bug, vă rugăm să raporteze la dezvoltatori.< Writing the HTML file failed. Scrierea fișierului HTML a eșuat. - - Export Confirmation - Confirmare la export - - - You are about to export your database to an unencrypted file. This will leave your passwords and sensitive information vulnerable! Are you sure you want to continue? - Ești pe cale să exporti baza de date într-un fișier necriptat. Acest lucru va lăsa parolele și informațiile dvs. sensibile vulnerabile! Esti sigur ca vrei sa continui? - - - New Database - Bază de date nouă - - - %1 [New Database] - Database tab name modifier - %1 [bază de date nouă] - - - %1 [Locked] - Database tab name modifier - %1 [blocat] - Export database to XML file @@ -2294,12 +2567,34 @@ Acest lucru este cu siguranta un bug, vă rugăm să raporteze la dezvoltatori.< Writing the XML file failed + + Export Confirmation + Confirmare la export + + + You are about to export your database to an unencrypted file. This will leave your passwords and sensitive information vulnerable! Are you sure you want to continue? + Ești pe cale să exporti baza de date într-un fișier necriptat. Acest lucru va lăsa parolele și informațiile dvs. sensibile vulnerabile! Esti sigur ca vrei sa continui? + + + %1 [Locked] + Database tab name modifier + %1 [blocat] + + + %1 [Temporary] + Database tab name modifier + + DatabaseWidget + + Searches and Tags + Căutări și etichete + Searching… - + Se caută... Shared group… @@ -2307,11 +2602,11 @@ Acest lucru este cu siguranta un bug, vă rugăm să raporteze la dezvoltatori.< Confirm Auto-Type - + Confirmă auto-tastarea Perform Auto-Type into the previously active window? - + Efectuează Auto-tastare în fereastra activă anterior? Execute command? @@ -2343,7 +2638,11 @@ Acest lucru este cu siguranta un bug, vă rugăm să raporteze la dezvoltatori.< Expired entries - + Intrări expirate + + + Entries expiring within %1 day(s) + No current database. @@ -2369,6 +2668,18 @@ Acest lucru este cu siguranta un bug, vă rugăm să raporteze la dezvoltatori.< No Results Nu sunt rezultate + + Save + Salvează + + + Enter a unique name or overwrite an existing search from the list: + + + + Save Search + Salvați căutarea + Lock Database? Blocarea bazei de date? @@ -2397,26 +2708,6 @@ Salvați modificările? File has changed Fișierul a fost modificat - - The database file has changed. Do you want to load the changes? - Fișierul bazei de date a fost modificat. Doriți să încărcați ultimele modificări? - - - Merge Request - Cerere îmbinare - - - The database file has changed and you have unsaved changes. -Do you want to merge your changes? - Fișierul bazei de date s-a modificat și aveți modificări nesalvate. -Doriți să îmbinați modificările? - - - Could not open the new database file while attempting to autoreload. -Error: %1 - Imposibil de deschis noul fișier bază de date în timp ce încercați să autoreload. -Eroare: %1 - Disable safe saves? Dezactivați salvarea sigură? @@ -2445,7 +2736,7 @@ Dezactivați salvarea sigură și încercați din nou? Save database backup - + Salvare copie de siguranță a bazei de date Empty recycle bin? @@ -2459,24 +2750,93 @@ Dezactivați salvarea sigură și încercați din nou? Could not find database file: %1 - - Entries expiring within %1 day(s) - + + New Database + Bază de date nouă - Searches and Tags + %1 [New Database] + Database tab name modifier + %1 [bază de date nouă] + + + Remote Sync did not contain any download or upload commands. - Enter a unique name or overwrite an existing search from the list: + Remote sync '%1' completed successfully! - Save - Salvează + Remote sync '%1' failed: %2 + - Save Search + Error while saving database %1: %2 + + + + Downloading... + Descărcarea... + + + Uploading... + + + + Syncing... + + + + Remove passkey from entry + + + + Do you want to remove the passkey from this entry? + + + + The database file "%1" was modified externally + + + + Do you want to load the changes? + + + + Reload database + + + + Reloading database… + + + + Reload canceled + + + + Reload successful + + + + Reload pending user action… + + + + The database file "%1" was modified externally.<br>How would you like to proceed?<br><br>Merge all changes<br>Ignore the changes on disk until save<br>Discard unsaved changes + + + + The database file "%1" was modified externally.<br>How would you like to proceed?<br><br>Merge all changes then save<br>Overwrite the changes on disk<br>Discard unsaved changes + + + + Database file overwritten. + + + + Database file on disk cannot be unlocked with current credentials.<br>Enter new credentials and/or present hardware key to continue. @@ -2496,7 +2856,7 @@ Dezactivați salvarea sigură și încercați din nou? Auto-Type - Auto tiparire + Auto-tastare Browser Integration @@ -2530,10 +2890,6 @@ Dezactivați salvarea sigură și încercați din nou? n/a nu se aplică - - (encrypted) - (criptat) - Select private key Selectați cheia privată @@ -2565,19 +2921,23 @@ Unfortunately, any changes made have been lost. Auto-Type Validation Error - + Eroare de validare la Auto-tastare An error occurred while validating the custom Auto-Type sequence: %1 Would you like to correct it? - + A apărut o eroare la validarea secvenței de Auto-tastare personalizare: +%1 +Doriți să o corectați? An error occurred while validating the Auto-Type sequence for "%1": %2 Would you like to correct it? - + A apărut o eroare la validarea secvenței de Auto-tastare pentru "%1": +%2 +Doriți să o corectați? Entry updated successfully. @@ -2609,12 +2969,16 @@ Would you like to correct it? [PROTECTED] Press Reveal to view or edit - + Apăsați Revelați pentru a vizualiza sau edita Hide Ascunde + + %n hour(s) + + %n week(s) % n săptămână (i)% n săptămână (i)%n săptămână(i) @@ -2627,9 +2991,9 @@ Would you like to correct it? %n year(s) % n an (i)% n an (i)%n an(i) - - %n hour(s) - + + Failed to decrypt SSH key, ensure password is correct. + @@ -2696,7 +3060,7 @@ Would you like to correct it? Exclude from database reports - + Excludere din rapoartele bazei de date Foreground Color: @@ -2719,23 +3083,23 @@ Would you like to correct it? EditEntryWidgetAutoType Enable Auto-Type for this entry - Activare tiparire automat pentru această intrare + Activează auto-tastare pentru această înregistrare Inherit default Auto-Type sequence from the group - + Moștenește secvența implicită de Auto-tastare de la grup Use custom Auto-Type sequence: - + Folosește secvență de Auto-tastare personalizată: Custom Auto-Type sequence - Secvență personalizată Auto-Type + Secvență personalizată de Auto-tastare Open Auto-Type help webpage - Deschideți pagina web de ajutor Auto-Type + Deschide pagina web de ajutor pentru Auto-tastare Window Associations @@ -2749,10 +3113,20 @@ Would you like to correct it? Add new window association Adăugați asociere fereastră nouă + + + + Add item + + + Remove selected window association Eliminați asocierea ferestrei selectată + + - + Remove item + - + Window title: Titlu fereastră: @@ -2775,25 +3149,11 @@ Would you like to correct it? Custom Auto-Type sequence for this window - Secvență personalizată de tip automat pentru această fereastră - - - + - Add item - + - - - - - Remove item - - + Secvență personalizată de Auto-tastare pentru această fereastră EditEntryWidgetBrowser - - These settings affect to the entry's behaviour with the browser extension. - Aceste setări afectează comportamentul intrării cu extensia browserului. - General General @@ -2806,26 +3166,14 @@ Would you like to correct it? Skip Auto-Submit for this entry Sariți la Trimitere automată pentru această intrare - - Only send this setting to the browser for HTTP Auth dialogs. If enabled, normal login forms will not show this entry for selection. - - Use this entry only with HTTP Basic Auth - - Do not send this setting to the browser for HTTP Auth dialogs. If enabled, HTTP Auth dialogs will not show this entry for selection. - - Do not use this entry with HTTP Basic Auth - - Additional URL's - Adresa URL suplimentară - Add Adaugă @@ -2838,6 +3186,22 @@ Would you like to correct it? Edit Editați + + These settings affect the entry's behaviour with the browser extension. + + + + Additional URLs + + + + Only send this entry to the browser for HTTP Auth dialogs. If enabled, normal login forms will not show this entry for selection. + + + + Do not send this entry to the browser for HTTP Auth dialogs. If enabled, HTTP Auth dialogs will not show this entry for selection. + + EditEntryWidgetHistory @@ -2882,7 +3246,7 @@ Would you like to correct it? EditEntryWidgetMain Edit Entry - + Editați intrarea Notes field @@ -2930,7 +3294,7 @@ Would you like to correct it? Tags list - + Listă de etichete &Username: @@ -3003,19 +3367,6 @@ Would you like to correct it? Private key Cheie privată - - External file - Fișier extern - - - Browser for key file - Browser pentru fișierul cheie - - - Browse… - Button for opening file dialog - - Attachment Atașament @@ -3032,6 +3383,23 @@ Would you like to correct it? Remove from agent Elimină din agent + + External file + Fișier extern + + + Browser for key file + Browser pentru fișierul cheie + + + Browse… + Button for opening file dialog + Răsfoiți... + + + Generate + Generează + Select attachment file Selectați fișierul de atașament @@ -3056,6 +3424,10 @@ Would you like to correct it? seconds secunde + + Clear agent + + EditGroupWidget @@ -3067,10 +3439,6 @@ Would you like to correct it? Icon Icon - - Browser Integration - Integrare cu browserul - Properties Proprietăți @@ -3087,6 +3455,10 @@ Would you like to correct it? Group has unsaved changes + + Browser Integration + Integrare cu browserul + Enable Activează @@ -3146,6 +3518,14 @@ Would you like to correct it? Omit WWW subdomain from matching toggle for this and sub groups + + Restrict matching to given browser key: + + + + Restrict matching to given browser key toggle for this and sub groups + + EditGroupWidgetKeeShare @@ -3179,7 +3559,7 @@ Would you like to correct it? Browse… - + Răsfoiți... Clear fields @@ -3281,15 +3661,15 @@ Extensiile acceptate sunt: %1. Use default Auto-Type sequence of parent group - + Folosește secvența implicită de Auto-tastare a grupului părinte Auto-Type: - + Auto-tastare: Search: - + Căutare: Auto-Type toggle for this and sub groups @@ -3301,7 +3681,7 @@ Extensiile acceptate sunt: %1. Default auto-type sequence field - Câmpul de secvență implicit de tip automat + Câmpul de secvență implicit de auto-tastare Notes field @@ -3313,7 +3693,7 @@ Extensiile acceptate sunt: %1. Set default Auto-Type sequence - + Setează secvența implicită de Auto-tastare Search toggle for this and sub groups @@ -3378,10 +3758,6 @@ Extensiile acceptate sunt: %1. Unable to fetch favicon. Nu pot descărca favicon. - - You can enable the DuckDuckGo website icon service under Tools -> Settings -> Security - Puteți activa serviciul de pictogramă a site-ului web DuckDuckGo în Instrumente -> Setări -> Securitate - Existing icon selected. Pictograma existentă selectată. @@ -3414,6 +3790,10 @@ Extensiile acceptate sunt: %1. The following icon(s) failed: Pictograma (ele) următoare nu a reușit:Pictograma (ele) următoare nu a reușit:Pictograma(e) următoare nu au reușit: + + You can enable the DuckDuckGo website icon service under Application Settings -> Security + + EditWidgetProperties @@ -3490,6 +3870,23 @@ Acest lucru poate provoca moduluri afectate la defecțiune. %1 - Clone %1 - Clona + + Passkey + Cheie de acces + + + Invalid conversion type: %1 + + + + Invalid conversion syntax: %1 + + + + Invalid regular expression syntax %1 +%2 + + EntryAttachments @@ -3498,6 +3895,21 @@ Acest lucru poate provoca moduluri afectate la defecțiune. + + EntryAttachmentsDialog + + Form + Formular + + + File name + + + + File contents... + + + EntryAttachmentsModel @@ -3535,14 +3947,6 @@ Acest lucru poate provoca moduluri afectate la defecțiune. Remove Înlătură - - Rename selected attachment - - - - Rename - - Open selected attachment Deschideți atașamentul selectat @@ -3619,11 +4023,6 @@ Acest lucru poate provoca moduluri afectate la defecțiune. Confirm Overwrite Attachment - - Attachment "%1" already exists. -Would you like to overwrite the existing attachment? - - Confirm Attachment @@ -3642,7 +4041,8 @@ Are you sure to add this file? The attachment '%1' was modified. Do you want to save the changes to your database? - + Atașamentul '%1' a fost modificat. +Doriți să salvați modificările în baza de date? Saving attachment failed @@ -3653,6 +4053,23 @@ Do you want to save the changes to your database? Error: %1 + + Attachment "%1" already exists. +Would you like to overwrite the existing attachment? + + + + New + + + + Preview + Previzualizare + + + Failed to preview an attachment: Attachment not found + + EntryAttributesModel @@ -3693,7 +4110,7 @@ Error: %1 Password - Parola + Parolă URL @@ -3733,11 +4150,11 @@ Error: %1 Auto-Type - Auto tiparire + Auto-tastare Tags - + Etichete @@ -3847,6 +4264,14 @@ Error: %1 Has TOTP + + Background Color + + + + Group Path + + EntryPreviewWidget @@ -3867,8 +4292,8 @@ Error: %1 Parola - Notes - Notițe + URL + URL Expiration @@ -3876,19 +4301,19 @@ Error: %1 Tags - + Etichete Tags list - + Listă de etichete Username Nume utilizator - URL - URL + Notes + Notițe Advanced @@ -3904,7 +4329,7 @@ Error: %1 Autotype - autotipie + Auto-tastare Default Sequence @@ -3938,6 +4363,10 @@ Error: %1 Never Niciodată + + Double click to copy value + Dublu clic pentru a copia valoarea + Enabled Activat @@ -3946,13 +4375,9 @@ Error: %1 Disabled Dezactivat - - Double click to copy value - - Double click to copy to clipboard - + Dublu clic pentru a copia în clipboard @@ -4147,7 +4572,7 @@ This will leave your passwords and sensitive information vulnerable! HibpDownloader Online password validation failed - + Validarea parolei online a eșuat @@ -4180,11 +4605,11 @@ Puteți activa serviciul pictogramelor site-ului web DuckDuckGo în secțiunea d Please wait, processing entry list… - + Vă rugăm să așteptați, se procesează lista de intrări... Downloading… - + Se descarcă... Ok @@ -4200,6 +4625,193 @@ Puteți activa serviciul pictogramelor site-ului web DuckDuckGo în secțiunea d Downloading favicons (%1/%2)… + Se descarcă pictogramele (%1/%2)... + + + + ImportWizard + + Import Wizard + Asistent de import + + + + ImportWizardPageReview + + WizardPage + Pagină de start + + + Entry count: %1 + Numărul de intrări: %1 + + + Group + Grup + + + Title + Titlu + + + Username + Nume utilizator + + + Password + Parolă + + + Url + URL + + + Could not load key file. + + + + Could not open remote database. Password or key file may be incorrect. + + + + + ImportWizardPageSelect + + Form + De la + + + Import File Selection + Selectarea fișierului de import + + + Password: + Parola: + + + Key File: + Fișier cheie: + + + Browse… + Răsfoiți... + + + Import Into: + Importați în: + + + New Database + Bază de date nouă + + + No unlocked databases available + Nu sunt disponibile baze de date deblocate + + + Existing Database: + Bază de date existentă: + + + Import File: + Importați fișierul: + + + Comma Separated Values (.csv) + Valori separate prin virgulă (.csv) + + + 1Password Export (.1pux) + + + + 1Password Vault (.opvault) + + + + Bitwarden (.json) + + + + KeePass 1 Database (.kdb) + + + + Open OPVault + + + + Select import file + Selectați fișierul de import + + + All files + Toate fișierele + + + Key files + Fișiere cheie + + + Select key file + Selectați fișier cheie + + + Comma Separated Values + Valori separate prin virgulă + + + 1Password Export + + + + Bitwarden JSON Export + + + + 1Password Vault + + + + KeePass1 Database + + + + Proton Pass (.json) + + + + Proton Pass JSON Export + + + + Temporary Database + + + + Command: + + + + e.g.: "sftp user@hostname" or "scp user@hostname:DatabaseOnRemote.kdbx {TEMP_DATABASE}" + + + + Input: + + + + e.g.: +get DatabaseOnRemote.kdbx {TEMP_DATABASE} +exit +--- +{TEMP_DATABASE} is used as placeholder to store the database in a temporary location +The command has to exit. In case of `sftp` as last commend `exit` has to be sent + + + + + Remote Database (.kdbx) @@ -4476,7 +5088,10 @@ Dacă reîncepe, atunci fișierul dvs. de bază de date poate fi corupt. - + Fișierul selectat este o bază de date veche KeePass 1 (.kdb). + +Puteți să o importați făcând clic pe Bază de date > „Import KeePass 1 database...”. +Aceasta este o migrare unidirecțională. Nu veți putea deschide baza de date importată cu vechea versiune KeePassX 0.4. Not a KeePass database. @@ -4527,7 +5142,7 @@ Linia %2, coloana %3 Invalid EnableAutoType value - Valoare nevalidă pentru permite AutoTiparire + Valoare invalidă pentru permiterea auto-tastării Invalid EnableSearching value @@ -4579,7 +5194,7 @@ Linia %2, coloana %3 Auto-type association window or sequence missing - Lipsă de fereastra de asociere de tiparire auto sau secvența + Lipsește fereastra de asociere sau secvența de auto-tastare Invalid bool value @@ -4634,17 +5249,6 @@ Linia %2, coloana %3 Deschiderea cheii private a eșuat - - KeePass1OpenWidget - - Import KeePass1 Database - Importați baza de date KeePass1 - - - Unable to open the database. - Nu pot deschide baza de date. - - KeePass1Reader @@ -4881,11 +5485,11 @@ Dacă reîncepe, atunci fișierul dvs. de bază de date poate fi corupt. Generate a new key file or choose an existing one to protect your database. - + Generați un nou fișier cheie sau alegeți unul existent pentru a vă proteja baza de date. Note: Do NOT use a file that may change as that will prevent you from unlocking your database. - + Notă: NU utilizați un fișier care se poate modifica, deoarece acest lucru vă va împiedica să deblocați baza de date. Browse for key file @@ -4893,7 +5497,7 @@ Dacă reîncepe, atunci fișierul dvs. de bază de date poate fi corupt. Browse… - + Răsfoiți... Old key file format @@ -4931,7 +5535,7 @@ Mesaj: %2 <p>You can add a key file containing random bytes for additional security.</p><p>You must keep it secret and never lose it or you will be locked out.</p> - + <p>Puteți adăuga un fișier cheie care conține octeți aleatori pentru o securitate suplimentară.</p><p>Trebuie să îl păstrați secret și să nu îl pierdeți niciodată, altfel veți fi blocat.</p> Key files @@ -5001,10 +5605,6 @@ Sigur doriți să continuați cu acest fișier? &Recent Databases &Baze de date recente - - &Import - &Import - &Export &Export @@ -5015,16 +5615,20 @@ Sigur doriți să continuați cu acest fișier? &Entries - + &Intrări Copy Att&ribute - + Copiați at&ributul TOTP TOTP + + Tags + Etichete + &Groups &Grupuri @@ -5035,11 +5639,11 @@ Sigur doriți să continuați cu acest fișier? View - + Vizualizați Theme - + Temă &Quit @@ -5069,45 +5673,25 @@ Sigur doriți să continuați cu acest fișier? &New Database… &Bază de date nouă... - - Create a new database - Crearea unei baze de date noi - &Merge From Database… - - - - Merge from another KDBX database - Îmbinare dintr-o altă bază de date KDBX + &Îmbinare din bază de date... &New Entry… - - - - Add a new entry - Adăugarea unei noi intrări + &Intrare nouă... &Edit Entry… - - - - View or edit entry - Vizualizarea sau editarea intrării + &Editare intrare &Delete Entry… - + &Ștergeți intrarea... &New Group… - - - - Add a new group - Adăugarea unui grup nou + &Grup nou... &Edit Group… @@ -5115,11 +5699,11 @@ Sigur doriți să continuați cu acest fișier? &Delete Group… - + &Ștergeți grupul... Download All &Favicons… - + Descărcare toate &favicoanele... Sort &A-Z @@ -5131,63 +5715,39 @@ Sigur doriți să continuați cu acest fișier? Sa&ve Database As… - + &Salvare bază de date ca... Database &Security… - + Securitate bază de date... Database &Reports… - - - - Statistics, health check, etc. - + &Rapoarte bază de date... &Database Settings… Setări bază de &date... - - Database settings - Setări bază de date - &Clone Entry… - + &Intrare clonă... Move u&p - - Move entry one step up - - Move do&wn - - Move entry one step down - - Copy &Username - - - - Copy username to clipboard - Copiere nume utilizator în Clipboard + Copiați &numele de utilizator Copy &Password - - - - Copy password to clipboard - Copiere parolă în Clipboard + Copiați &parola &Settings @@ -5199,11 +5759,11 @@ Sigur doriți să continuați cu acest fișier? Perform &Auto-Type - Efectuați și &Auto-Tiparire + Efectuează &Auto-tastare Download &Favicon - + Descărcare &favicon Open &URL @@ -5211,32 +5771,24 @@ Sigur doriți să continuați cu acest fișier? &Lock Database - + &Blocați baza de date Lock &All Databases - + Blocați &toate bazele de date &Title &Titlu - Copy title to clipboard - Copiere titlu în Clipboard - - - Copy URL to clipboard - Copiere URL în Clipboard + Copy &URL + Copiați &URL-ul &Notes &Notițe - - Copy notes to clipboard - Copierea notelor în Clipboard - &CSV File… @@ -5249,33 +5801,21 @@ Sigur doriți să continuați cu acest fișier? KeePass 1 Database… - - Import a KeePass 1 database - Importul unei baze de date KeePass 1 - 1Password Vault… - - Import a 1Password Vault - Import 1Password Vault - CSV File… Fișier CSV... - - Import a CSV file - Importul unui fișier CSV - Show TOTP - + Afișare TOTP Show QR Code - + Afișare cod QR Set up TOTP… @@ -5285,6 +5825,10 @@ Sigur doriți să continuați cu acest fișier? Copy &TOTP Copiază &TOTP + + Copy Password and TOTP + Copiați parola și TOTP + E&mpty recycle bin coș de r&eciclare gol @@ -5295,7 +5839,7 @@ Sigur doriți să continuați cu acest fișier? Report a &Bug - + Raportați o eroare &Getting Started @@ -5307,11 +5851,7 @@ Sigur doriți să continuați cu acest fișier? &Online Help - - - - Go to online documentation - + &Ajutor online &User Guide @@ -5327,7 +5867,7 @@ Sigur doriți să continuați cu acest fișier? Save Database Backup… - + Salvați copia de siguranță a bazei de date... Add key to SSH Agent @@ -5339,35 +5879,39 @@ Sigur doriți să continuați cu acest fișier? Compact Mode - + Modul compact Automatic - + Automată Light - + Deschisă Dark - + Întunecată Classic (Platform-native) - + Clasică (platformă-nativă) + + + Show Menubar + Afișați meniul Show Toolbar - + Afișați bara de instrumente Show Preview Panel - + Afișare panou de previzualizare Always on Top - + Mereu deasupra Hide Usernames @@ -5379,6 +5923,10 @@ Sigur doriți să continuați cu acest fișier? Clone Group... + Clonează grupul... + + + &XML File… @@ -5391,13 +5939,15 @@ Sigur doriți să continuați cu acest fișier? Don't show again for this version - + Nu se afișează din nou pentru această versiune WARNING: You are using an unstable build of KeePassXC. There is a high risk of corruption, maintain a backup of your databases. This version is not meant for production use. - + AVERTISMENT: Folosiți o versiune instabilă a KeePassXC. +Există un risc ridicat de corupție, păstrați o copie de siguranță a bazelor de date. +Această versiune nu este destinată utilizării în producție. NOTE: You are using a pre-release version of KeePassXC. @@ -5405,9 +5955,8 @@ Expect some bugs and minor issues, this version is meant for testing purposes. - WARNING: Your Qt version may cause KeePassXC to crash with an On-Screen Keyboard. -We recommend you use the AppImage available on our downloads page. - + No Tags + Fără etichete Restore Entry(s) @@ -5437,6 +5986,10 @@ We recommend you use the AppImage available on our downloads page. Quit KeePassXC Părăsiți KeePassXC + + %1 Entry(s) + + Please present or touch your YubiKey to continue… @@ -5449,38 +6002,314 @@ We recommend you use the AppImage available on our downloads page. You must restart the application to apply this setting. Would you like to restart now? - - Tags - - - - No Tags - - - - %1 Entry(s) - - - - Copy Password and TOTP - - - - &XML File… - - - - XML File… - - - - Copy &URL - - Allow Screen Capture + + 1Password 1PUX... + + + + Import a 1Password 1PUX file + + + + Import… + + + + Passkeys… + + + + Import Passkey + Importare cheie de acces + + + Remote S&ync… + + + + Quit Application + + + + Open About Dialog + + + + Open Database + Deschideți baza de date + + + Create Database + Creați o bază de date + + + Merge From Database + + + + Create Entry + + + + Edit Entry + Editați intrarea + + + Delete Entry + + + + Create Group + + + + Edit Group + + + + Delete Group + + + + Download All Favicons + + + + Sort Groups A-Z + + + + Sort Groups Z-A + + + + Save Database As + + + + Show Database Security + + + + Show Database Reports + + + + Show Database Settings + + + + Show Passkeys + + + + Clone Entry + + + + Move Entry Up + + + + Move Entry Down + + + + Copy Username + Copiați numele de utilizator + + + Copy Password + Copiați parola + + + Show Application Settings + + + + Show Password Generator + + + + Remove Passkey From Entry + + + + Perform Auto-Type: {USERNAME} + + + + Perform Auto-Type: {USERNAME}{ENTER} + + + + Perform Auto-Type: {PASSWORD} + + + + Perform Auto-Type: {PASSWORD}{ENTER} + + + + Perform Auto-Type: {TOTP} + + + + Copy Title + + + + Copy URL + + + + Copy Notes + + + + Export to CSV + + + + Export to HTML + + + + Import KeePass1 Database + Importați baza de date KeePass1 + + + Import 1Password Vault + + + + Import CSV File + + + + Show TOTP QR Code + + + + Set up TOTP + + + + Empty Recycle Bin + + + + Open Donation Website + + + + Open Bug Report + + + + Open Online Documentation + + + + Open Keyboard Shortcuts Guide + + + + Save Database Backup + + + + SSH Agent: Add Key + + + + SSH Agent: Remove Key + + + + Toggle Compact Mode + + + + Set Theme: Automatic + + + + Set Theme: Light + + + + Set Theme: Dark + + + + Set Theme: Classic + + + + Toggle Show Menubar + Comutați afișare meniu + + + Toggle Show Toolbar + + + + Toggle Show Preview Panel + + + + Toggle Always on Top + + + + Toggle Hide Usernames + + + + Toggle Hide Passwords + + + + Export to XML + + + + Toggle Allow Screen Capture + + + + Show Group Panel + + + + Toggle Show Group Panel + + + + Setup Remote Sync… + + + + Password Generator + Generator de parole + + + E&xpire Entry… + + + + Clear SSH Agent + + + + Clear all identities in ssh-agent + + ManageDatabase @@ -5521,7 +6350,7 @@ We recommend you use the AppImage available on our downloads page. Reset any remembered decisions for this application - + Resetează toate deciziile reținute pentru această aplicație @@ -5538,26 +6367,6 @@ We recommend you use the AppImage available on our downloads page. Overwriting %1 [%2] Suprascrierea %1 [%2] - - older entry merged from database "%1" - intrare mai veche îmbinată din baza de date "%1" - - - Adding backup for older target %1 [%2] - Adăugarea copiei de rezervă pentru ținta mai veche %1 [%2] - - - Adding backup for older source %1 [%2] - Adăugarea copiei de rezervă pentru sursa mai veche %1 [%2] - - - Reapplying older target entry on top of newer source %1 [%2] - Reaplicarea intrării țintă mai vechi în partea de sus a sursei mai noi %1 [%2] - - - Reapplying older source entry on top of newer target %1 [%2] - Reaplicarea intrării sursei mai vechi în partea de sus a țintei mai noi %1 [%2] - Synchronizing from newer source %1 [%2] Sincronizarea din sursa mai nouă %1 [%2] @@ -5595,7 +6404,7 @@ We recommend you use the AppImage available on our downloads page. NewDatabaseWizard Create a new KeePassXC database… - + Crearea unei noi baze de date KeePassXC... Root @@ -5617,24 +6426,16 @@ We recommend you use the AppImage available on our downloads page. Here you can adjust the database encryption settings. Don't worry, you can change them later in the database settings. Aici aveți posibilitatea să ajustați setările de criptare a bazei de date. Nu vă faceți griji, le puteți modifica mai târziu în setările bazei de date. - - Advanced Settings - Setări avansate - - - Simple Settings - Setări simple - NewDatabaseWizardPageDatabaseKey Database Credentials - + Credențiale pentru baza de date A set of credentials known only to you that protects your database. - + Un set de credențiale cunoscute doar de dvs. care vă protejează baza de date. @@ -5659,6 +6460,25 @@ We recommend you use the AppImage available on our downloads page. Vă rugăm să completați numele afișat și o descriere opțională pentru noua bază de date: + + NewEntryAttachmentsDialog + + Attachment name cannot be empty + + + + Attachment with the same name already exists + + + + Save attachment + Salvează atașament + + + New entry attachment + + + NixUtils @@ -5705,15 +6525,6 @@ We recommend you use the AppImage available on our downloads page. Se așteaptă %1 octeți de text clar, %2 găsit - - OpVaultOpenWidget - - Read Database did not produce an instance -%1 - Citirea bazei de date nu a produs o instanță -%1 - - OpVaultReader @@ -5787,6 +6598,10 @@ We recommend you use the AppImage available on our downloads page. Unknown cipher: %1 Cifru necunoscut: %1 + + AES-256/GCM is currently not supported + + Passphrase is required to decrypt this key Passphrase este necesar pentru a decripta această tastă @@ -5852,9 +6667,182 @@ We recommend you use the AppImage available on our downloads page. EOF neașteptate atunci când scrierea cheie privată - AES-256/GCM is currently not supported + (encrypted) + (criptat) + + + + OpenSSHKeyGenDialog + + SSH Key Generator + + Type + Tip + + + Bits + + + + Comment + Comentariu + + + + PasskeyExportDialog + + KeePassXC - Passkey Export + KeePassXC - Export de chei de acces + + + Filenames will be generated with title and .passkey file extension. + + + + Export entries + Exportul intrărilor + + + Export Selected + + + + Cancel + Anulare + + + Export to folder + + + + Export the following passkey entries. + + + + + PasskeyExporter + + KeePassXC: Passkey Export + KeePassXC - Export de chei de acces + + + File "%1.passkey" already exists. +Do you want to overwrite it? + + + + + Cannot open file + + + + Cannot open file "%1" for writing. + + + + Cannot write to file + + + + + PasskeyImportDialog + + KeePassXC - Passkey Import + KeePassXC - Import cheie de acces + + + Username: %1 + + + + Group + Grup + + + Database + Bază de date + + + Import Passkey + Importare cheie de acces + + + Import + Import + + + Cancel + Anulare + + + Entry + Intrare + + + Create new entry + Creați o intrare nouă + + + Relying Party: %1 + + + + Import the following passkey: + Importați următoarea cheie de acces: + + + Import the following passkey to this entry: + Importați următoarea cheie de acces în această intrare: + + + Default passkeys group (Imported Passkeys) + Grup de chei de acces implicite (chei de acces importate) + + + + PasskeyImporter + + Passkey file + Fișier cheie de acces + + + All files + Toate fișierele + + + Cannot open file + + + + Cannot open file "%1" for reading. + + + + Open passkey file + Deschidere fișier cheie de acces + + + Cannot import passkey + Nu se poate importa cheia de acces + + + Cannot import passkey file "%1". Data is missing. + Nu se poate importa fișierul de chei de acces "%1". Datele lipsesc. + + + Cannot import passkey file "%1". +The following data is missing: +%2 + Nu se poate importa fișierul de chei de acces "%1". +Următoarele date lipsesc: +%2 + + + Cannot import passkey file "%1". Private key is missing or malformed. + Nu se poate importa fișierul de chei de acces "%1". Cheia privată lipsește sau este deformată. + PasswordEditWidget @@ -6058,26 +7046,18 @@ We recommend you use the AppImage available on our downloads page. Word Count: Număr cuvinte: - - Character Count: - - Word Case: Registrul cuvântelor Delete selected wordlist - + Ștergerea listei de cuvinte selectate Add custom wordlist - - character - - Close Închide @@ -6114,17 +7094,41 @@ We recommend you use the AppImage available on our downloads page. Entropy: %1 bit Entropie: %1 bit + + Password Quality: %1 + Calitate parolă: %1 + + + Poor + Password quality + Inacceptabil + + + Weak + Password quality + Slab + + + Good + Password quality + Bun + + + Excellent + Password quality + Excelent + Confirm Delete Wordlist - + Confirmați ștergerea listei de cuvinte Do you really want to delete the wordlist "%1"? - + Chiar doriți să ștergeți lista de cuvinte "%1"? Failed to delete wordlist - + Nu s-a reușit ștergerea listei de cuvinte Wordlists @@ -6160,32 +7164,20 @@ Do you want to overwrite it? Caractere speciale - Password Quality: %1 - Calitate parolă: %1 + passwordLength + - Poor - Password quality - Inacceptabil + Characters: %1 + - Weak - Password quality - Slab + MIXED case + - Good - Password quality - Bun - - - Excellent - Password quality - Excelent - - - Excluded characters: "0", "1", "l", "I", "O", "|", "﹒" - Caractere excluse: "0", "1", "l", "I", "O", "|", "." + Excluded characters: "0", "1", "l", "I", "O", "|", "﹒", "B", "8", "G", "6" + @@ -6208,7 +7200,7 @@ Do you want to overwrite it? Warning: Caps Lock enabled! - + Avertisment: Caps Lock este activat! Quality: %1 @@ -6235,7 +7227,7 @@ Do you want to overwrite it? Excelent - Toggle password visibilty using Control + H. Open the password generator using Control + G. + Toggle password visibility using Control + H. Open the password generator using Control + G. @@ -6254,6 +7246,21 @@ Do you want to overwrite it? + + PreviewEntryAttachmentsDialog + + Preview entry attachment + + + + No preview available + + + + Image format not supported + + + QMessageBox @@ -6292,6 +7299,10 @@ Do you want to overwrite it? Continue Continua + + Continue with weak password + + QObject @@ -6578,19 +7589,19 @@ Do you want to overwrite it? Copy the given attribute to the clipboard. Defaults to "password" if not specified. Don't translate "password", it refers to the attribute. - + Copiați atributul dat în clipboard. Valoarea implicită este "password" dacă nu este specificată. Copy the current TOTP to the clipboard (equivalent to "-a totp"). - + Copiați TOTP-ul curent în clipboard (echivalent cu "-a totp"). Must match only one entry, otherwise a list of possible matches is shown. - + Trebuie să corespundă unei singure intrări, în caz contrar se afișează o listă de posibile corespondențe. Copy an entry's attribute to the clipboard. - + Copiați atributul unei intrări în clipboard. Path of the entry to clip. @@ -6599,7 +7610,7 @@ Do you want to overwrite it? Timeout before clearing the clipboard (default is %1 seconds, set to 0 for unlimited). - + Timpul de așteptare înainte de ștergerea clipboardului (valoarea implicită este %1 secunde, setată la 0 pentru nelimitat). Invalid timeout value %1. @@ -6607,7 +7618,7 @@ Do you want to overwrite it? Multiple entries matching: - + Potrivirea mai multor intrări: Using matching entry: %1 @@ -6635,7 +7646,7 @@ Do you want to overwrite it? Entry's "%1" attribute copied to the clipboard! - + Atributul "%1" al intrării a fost copiat în clipboard! Clearing the clipboard in %1 second(s)... @@ -6685,6 +7696,10 @@ Do you want to overwrite it? Too many arguments provided. + + Path of the database. + Calea către baza de date + Target decryption time in MS for the database. @@ -6705,10 +7720,6 @@ Do you want to overwrite it? Create a new database. Creează o bază de date nouă. - - Path of the database. - Calea către baza de date - Invalid decryption time %1. @@ -6753,6 +7764,158 @@ Do you want to overwrite it? Successfully created new database. Noua bază de date a fost creată cu succes. + + Unset the password for the database. + + + + Unset the key file for the database. + + + + Edit a database. + + + + Cannot use %1 and %2 at the same time. + + + + Could not change the database key. + + + + Database was not modified. + + + + Writing the database failed: %1 + Scrierea bazei de date nu a reușit: %1 + + + Successfully edited the database. + + + + Cannot remove password: The database does not have a password. + + + + Cannot remove file key: The database does not have a file key. + + + + Loading the new key file failed: %1 + Încărcarea noului fișier cheie a eșuat: %1 + + + Found unexpected Key type %1 + + + + Cannot remove all the keys from a database. + + + + Show a database's information. + Afișare informații despre o bază de date. + + + UUID: + UUID: + + + Name: + Nume: + + + Description: + Descriere: + + + Cipher: + Cifru: + + + KDF: + KDF: + + + Recycle bin is enabled. + + + + Recycle bin is not enabled. + + + + Location + Locație + + + Database created + Baza de date creată + + + Last saved + Ultima salvare + + + Unsaved changes + Modificări salvate + + + yes + da + + + no + Nu + + + Number of groups + Număr de grupuri + + + Number of entries + Numărul de intrări + + + Number of expired entries + Numărul de intrări expirate + + + Unique passwords + Parole unice + + + Non-unique passwords + Parole non-unice + + + Maximum password reuse + Reutilizarea maximă a parolei + + + Number of short passwords + Număr de parole scurte + + + Number of weak passwords + Număr de parole slabe + + + Entries excluded from reports + Mențiuni excluse din rapoarte + + + Average password length + Lungimea medie a parolei + + + %1 characters + %1 caractere + Word count for the diceware passphrase. Word conta pentru fraza de acces diceware. @@ -6776,10 +7939,6 @@ Do you want to overwrite it? Invalid word count %1 Număr de cuvinte nevalide %1 - - The word list is too small (< 1000 items) - Lista de cuvinte este prea mică (<1000 de articole) - Title for the entry. Titlu pentru intrare. @@ -6804,10 +7963,6 @@ Do you want to overwrite it? Enter new password for entry: Introduceți parola nouă pentru intrare: - - Writing the database failed: %1 - Scrierea bazei de date nu a reușit: %1 - Successfully edited entry %1. Intrare editată cu succes %1. @@ -6928,10 +8083,6 @@ Do you want to overwrite it? Exit interactive mode. Ieșiți din modul interactiv. - - Format to use when exporting. Available choices are 'xml' or 'csv'. Defaults to 'xml'. - - Exports the content of a database to standard output in the specified format. Exportă conținutul unei baze de date până la ieșirea standard în formatul specificat. @@ -7032,106 +8183,6 @@ Do you want to overwrite it? Successfully imported database. Baza de date importată cu succes. - - Show a database's information. - - - - UUID: - UUID: - - - Name: - Nume: - - - Description: - Descriere: - - - Cipher: - Cifru: - - - KDF: - KDF: - - - Recycle bin is enabled. - - - - Recycle bin is not enabled. - - - - Location - Locație - - - Database created - - - - Last saved - Ultima salvare - - - Unsaved changes - Modificări salvate - - - yes - da - - - no - Nu - - - Number of groups - Număr de grupuri - - - Number of entries - Numărul de intrări - - - Number of expired entries - Numărul de intrări expirate - - - Unique passwords - Parole unice - - - Non-unique passwords - Parole non-unice - - - Maximum password reuse - Reutilizarea maximă a parolei - - - Number of short passwords - Număr de parole scurte - - - Number of weak passwords - Număr de parole slabe - - - Entries excluded from reports - - - - Average password length - Lungimea medie a parolei - - - %1 characters - %1 caractere - Unknown command %1 Comanda necunoscută %1 @@ -7304,6 +8355,10 @@ Comenzi disponibile: Show the protected attributes in clear text. Afișează atributele protejate într-un text clar. + + Show all the attributes of the entry. + Afișare toate atributele intrării. + Show the attachments of the entry. @@ -7361,7 +8416,10 @@ Comenzi disponibile: stop supporting in the future. Please consider generating a new key file. - + AVERTISMENT: Folosiți un format de fișier cheie vechi, pe care KeePassXC +s-ar putea să nu îl mai suporte în viitor. + +Vă rugăm să luați în considerare generarea unui nou fișier cheie. Invalid YubiKey slot %1 @@ -7371,13 +8429,17 @@ Please consider generating a new key file. Invalid YubiKey serial %1 + + Please present or touch your YubiKey to continue. + + Enter password to encrypt database (optional): Introduceți parola pentru criptarea bazei de date (opțional): Do you want to create a database with an empty password? [y/N]: - + Doriți să creați o bază de date cu o parolă goală? [y/N]: Repeat password: @@ -7502,7 +8564,7 @@ Nucleu (Kernel): %3 %4 Auto-Type - Auto tiparire + Auto-tastare SSH Agent @@ -7518,7 +8580,7 @@ Nucleu (Kernel): %3 %4 Quick Unlock - + Deblocare rapidă Secret Service Integration @@ -7608,18 +8670,6 @@ Nucleu (Kernel): %3 %4 file empty fișier gol - - malformed string - șir incorect - - - missing closing quote - lipsă citat de închidere - - - %1: (row, col) %2,%3 - % 1: (rând, col) %2,%3 - AES 256-bit AES 256-biți @@ -7708,7 +8758,7 @@ Nucleu (Kernel): %3 %4 Do you really want to delete the entry "%1" for good? - + Chiar doriți să ștergeți definitiv intrarea "%1"? Do you really want to delete %n entry(s) for good? @@ -7788,7 +8838,7 @@ Nucleu (Kernel): %3 %4 lock all open databases - + blochează toate bazele de date deschise key file of the database @@ -7798,18 +8848,18 @@ Nucleu (Kernel): %3 %4 read password of the database from stdin citi parola bazei de date de la stdin - - Locked databases. - - Database failed to lock. - + Nu s-a reușit blocarea bazei de date. Another instance of KeePassXC is already running. O altă instanță a KeePassXC este deja în execuție. + + KeePassXC is not running. No open database to lock + KeePassXC nu rulează. Nu există o bază de date deschisă pentru a fi blocată + Fatal error while testing the cryptographic functions. Eroare fatală în timpul testării funcțiilor criptografice. @@ -7842,7 +8892,7 @@ Nucleu (Kernel): %3 %4 Warning: Failed to block screenshot capture on a top-level window. - + Avertisment: Nu s-a reușit blocarea capturării capturii de ecran pe o fereastră de nivel superior. Invalid Cipher @@ -7853,74 +8903,300 @@ Nucleu (Kernel): %3 %4 - Please present or touch your YubiKey to continue. - - - - Show all the attributes of the entry. - - - - Edit a database. - - - - Could not change the database key. - - - - Database was not modified. - - - - Successfully edited the database. - - - - Loading the new key file failed: %1 - - - - Unset the password for the database. - - - - Unset the key file for the database. - - - - Cannot use %1 and %2 at the same time. - - - - Cannot remove all the keys from a database. - - - - Cannot remove password: The database does not have a password. - - - - Cannot remove file key: The database does not have a file key. - - - - Found unexpected Key type %1 - - - - Set the key file for the database. -This options is deprecated, use --set-key-file instead. - - - - KeePassXC is not running. No open database to lock - + Access to all entries is denied + Accesul la toate intrările este interzis allow screenshots and app recording (Windows/macOS) + + Set the key file for the database. +This option is deprecated, use --set-key-file instead. + + + + Databases have been locked. + Bazele de date au fost blocate. + + + Attestation not supported + + + + Credential is excluded + + + + Passkeys request canceled + + + + Invalid user verification + + + + Empty public key + + + + Invalid URL provided + + + + Passkeys + + + + AES initialization failed + + + + AES encrypt failed + + + + Failed to store in Linux Keyring + + + + Polkit returned an error: %1 + + + + Could not locate key in keyring + + + + Could not read key in keyring + + + + AES decrypt failed + + + + No Polkit authentication agent was available + + + + Polkit authorization failed + + + + No Quick Unlock provider is available + + + + Failed to init KeePassXC crypto. + + + + Failed to encrypt key data. + + + + Failed to get Windows Hello credential. + + + + Failed to decrypt key data. + + + + Origin is empty or not allowed + + + + Effective domain is not a valid domain + + + + Origin and RP ID do not match + + + + No supported algorithms were provided + + + + Wait for timer to expire + + + + Challenge is shorter than required minimum length + + + + user.id does not match the required length + + + + Favorite + Tag for favorite entries + + + + File does not exist. + + + + Cannot open file: %1 + + + + Cannot parse file: %1 at position %2 + + + + Failed to decrypt json file: %1 + + + + Invalid encKeyValidation field + + + + Invalid cipher list within encKeyValidation field + + + + Wrong password + + + + Invalid encrypted data field + + + + Invalid cipher list within encrypted data field + + + + Cannot initialize cipher + + + + Cannot decrypt data + + + + Bitwarden Import + + + + Archived + Tag for archived entries + + + + Invalid 1PUX file format: Not a valid ZIP file. + + + + Invalid 1PUX file format: Missing export.data + + + + 1Password Import + + + + Enter Shortcut + + + + Action + + + + Shortcuts + + + + Unknown passkeys error + + + + Invalid KDF iterations, cannot decrypt json file + + + + Unsupported format, ensure your Bitwarden export is password-protected + + + + Only PBKDF and Argon2 are supported, cannot decrypt json file + + + + Reset Shortcuts + + + + Double click an action to change its shortcut + + + + Filter... + + + + Shortcut Conflict + + + + Shortcut %1 conflicts with '%2'. Overwrite shortcut? + + + + Cannot generate valid passphrases because the wordlist is too short + + + + Encrypted files are not supported. + + + + Proton Pass Import + + + + Delete plugin data? + Ștergeți datele modulului? + + + Delete plugin data from Entry(s)? + + + + Passkey + Cheie de acces + + + Format to use when exporting. Available choices are 'xml', 'csv' or 'html'. Defaults to 'xml'. + + + + start minimized to the system tray + + + + malformed string, possible unescaped delimiter + + + + missing closing delimiter + + + + %1, row: %2, column: %3 + + + + Tags + Etichete + QtIOCompressor @@ -7956,23 +9232,42 @@ This options is deprecated, use --set-key-file instead. Eroare internă zlib: + + RemoteHandler + + Command `%1` did not finish in time. Process was killed. + + + + Failed to upload merged database. Command `%1` did not finish in time. Process was killed. + + + + Invalid download parameters provided. + + + + Command `%1` failed to download database. + + + + Invalid database pointer or upload parameters provided. + + + + Command `%1` exited with status code: %2 + + + + Failed to upload merged database. Command `%1` exited with status code: %2 + + + ReportsWidgetBrowserStatistics - - Exclude expired entries from the report - - - - Show only entries which have URL set - - - - Show only entries which have browser settings in custom data - - Double-click entries to edit. - + Faceți dublu clic pe intrări pentru a le edita. List of entry URLs @@ -8008,7 +9303,7 @@ This options is deprecated, use --set-key-file instead. No entries with a URL, or none has browser extension settings saved. - + Nu există intrări cu o adresă URL sau niciuna nu are setările extensiilor de browser salvate. Title @@ -8034,44 +9329,53 @@ This options is deprecated, use --set-key-file instead. Exclude from reports + + Expire Entry(s)… + + + + Only show entries that have a URL + Afișați numai intrările care au un URL + + + Only show entries that have been explicitly allowed or denied + Afișează numai intrările care au fost permise sau refuzate în mod explicit + + + Show expired entries + Afișați intrările expirate + + + (Expired) + + + + Delete plugin data from Entry(s)… + + ReportsWidgetHealthcheck - Exclude expired entries from the report - + Show expired entries + Afișați intrările expirate - Also show entries that have been excluded from reports + (Expired) Hover over reason to show additional details. Double-click entries to edit. - - - - Bad - Password quality - + Treceți peste motiv pentru a afișa detalii suplimentare. Faceți dublu clic pe intrări pentru a le edita. Bad — password must be changed - - Poor - Password quality - Inacceptabil - Poor — password should be changed - - Weak - Password quality - Slab - Weak — consider changing the password @@ -8120,6 +9424,14 @@ This options is deprecated, use --set-key-file instead. Exclude from reports + + Expire Entry(s)… + + + + Show entries that have been excluded from reports + + ReportsWidgetHibp @@ -8215,6 +9527,77 @@ This options is deprecated, use --set-key-file instead. Exclude from reports + + Expire Entry(s)… + + + + + ReportsWidgetPasskeys + + Export + Export + + + Import + Import + + + List of entry URLs + + + + Title + Titlu + + + Path + Cale + + + Username + Nume utilizator + + + URLs + + + + Edit Entry… + + + + Delete Entry(s)… + + + + Relying Party + + + + Show expired entries + Afișați intrările expirate + + + (Expired) + + + + Export Confirmation + Confirmare la export + + + The passkey file will be vulnerable to theft and unauthorized use, if left unsecured. Are you sure you want to continue? + + + + Please wait, list of entries with passkeys is being updated… + Vă rugăm să așteptați, lista de intrări cu chei de acces este în curs de actualizare... + + + No entries with passkeys. + Nu există intrări cu chei de acces. + ReportsWidgetStatistics @@ -8248,7 +9631,7 @@ This options is deprecated, use --set-key-file instead. Database created - + Baza de date creată Last saved @@ -8324,7 +9707,7 @@ This options is deprecated, use --set-key-file instead. Entries excluded from reports - + Mențiuni excluse din rapoarte Excluding entries from reports, e. g. because they are known to have a poor password, isn't necessarily a problem but you should keep an eye on them. @@ -8379,7 +9762,7 @@ This options is deprecated, use --set-key-file instead. Security keys are not supported by the agent or the security key provider is unavailable. - + Cheile de securitate nu sunt acceptate de agent sau furnizorul de chei de securitate nu este disponibil. No agent running, cannot remove identity. @@ -8389,6 +9772,14 @@ This options is deprecated, use --set-key-file instead. No agent running, cannot list identities. + + Failed to remove all SSH identities from agent. + + + + All SSH identities removed from agent. + + SearchHelpWidget @@ -8455,10 +9846,14 @@ This options is deprecated, use --set-key-file instead. Search Help Căutare ajutor + + Save Search + Salvați căutarea + Search (%1)… Search placeholder text, %1 is the keyboard shortcut - + Căutare (%1)... Case sensitive @@ -8468,10 +9863,6 @@ This options is deprecated, use --set-key-file instead. Limit search to selected group Limitați căutarea la grupul selectat - - Save Search - - SettingsClientModel @@ -8523,39 +9914,23 @@ This options is deprecated, use --set-key-file instead. Show notification when passwords are retrieved by clients - + Afișare notificare atunci când parolele sunt recuperate de către clienți <html><head/><body><p>If enabled, any attempt to read a password must be confirmed. Otherwise, clients can read passwords without confirmation when the database is unlocked.</p><p>This option only covers the access to the password of an entry. Clients can always enumerate the items of exposed databases and query their attributes.</p></body></html> - + Dacă este activată, orice încercare de a citi o parolă trebuie confirmată. În caz contrar, clienții pot citi parolele fără confirmare atunci când baza de date este deblocată. Această opțiune se referă numai la accesul la parola unei intrări. Clienții pot oricând să enumere elementele din bazele de date expuse și să interogheze atributele acestora. Confirm when passwords are retrieved by clients - - <html><head/><body><p><span style=" - font-family:'-apple-system','BlinkMacSystemFont','Segoe UI','Helvetica','Arial','sans-serif','Apple Color - Emoji','Segoe UI Emoji'; font-size:14px; color:#24292e; background-color:#ffffff;">This setting does - not override disabling recycle bin prompts</span></p></body></html> - - - Confirm when clients request entry deletion - - <html><head/><body><p>This improves compatibility with certain applications - which search for password without unlocking the database first.</p><p>But enabling this may also - crash the client if the database can not be unlocked within a certain timeout. (Usually 25s, but may be a - different value set in applications.)</p></body></html> - - - Prompt to unlock database before searching - + Solicitare de deblocare a bazei de date înainte de căutare Exposed database groups: @@ -8577,6 +9952,14 @@ This options is deprecated, use --set-key-file instead. Save current changes to activate the plugin and enable editing of this section. + + <html><head/><body><p>This setting does not override disabling recycle bin prompts </p></body></html> + + + + <html><head/><body><p>This improves compatibility with certain applications which search for password without unlocking the database first.</p><p>But enabling this may also crash the client if the database can not be unlocked within a certain timeout. (Usually 25s, but may be a different value set in applications.) </p></body></html> + <html><head/><body><p>Acest lucru îmbunătățește compatibilitatea cu anumite aplicații care caută parola fără să deblocheze mai întâi baza de date.</p><p>Dar activarea acestui lucru poate duce la blocarea clientului dacă baza de date nu poate fi deblocată într-un anumit interval de timp. (De obicei 25s, dar poate fi o valoare diferită stabilită în aplicații).  + SettingsWidgetKeeShare @@ -8644,7 +10027,7 @@ This options is deprecated, use --set-key-file instead. ShareImport Successful import - + Import reușit @@ -8684,6 +10067,14 @@ This options is deprecated, use --set-key-file instead. TagModel + + Clear Search + Ștergeți căutarea + + + All Entries + Toate intrările + Expired @@ -8692,14 +10083,6 @@ This options is deprecated, use --set-key-file instead. Weak Passwords - - All Entries - - - - Clear Search - - TagView @@ -8717,7 +10100,7 @@ This options is deprecated, use --set-key-file instead. Remove tag "%1" from all entries in this database? - + Eliminați eticheta "%1" din toate intrările din această bază de date? @@ -8864,7 +10247,7 @@ Exemplu: JBSWY3DPEHPK3PXP <strong>A new version is available.</strong><br/>KeePassXC %1 can be <a href="https://keepassxc.org/download/">downloaded here</a>. - + <strong>O nouă versiune este disponibilă.</strong><br/>KeePassXC %1 can be <a href="https://keepassxc.org/download/">downloaded here</a>. You have the latest version of KeePassXC @@ -8877,26 +10260,6 @@ Exemplu: JBSWY3DPEHPK3PXP Start storing your passwords securely in a KeePassXC database Începeți să stocați parolele în siguranță într-o bază de date KeePassXC - - Create new database - Creează o bază de date nouă - - - Open existing database - Deschide bază de date existentă - - - Import from KeePass 1 - Importă din KeePass 1 - - - Import from 1Password - Importă de la 1Password - - - Import from CSV - Importă din CSV - Recent databases Baze de date recente @@ -8909,6 +10272,18 @@ Exemplu: JBSWY3DPEHPK3PXP Welcome to KeePassXC %1 Bun venit la KeePassXC %1 + + Create Database + Creați o bază de date + + + Open Database + Deschideți o bază de date + + + Import File + Fișier de import + WinUtils @@ -8925,31 +10300,8 @@ Exemplu: JBSWY3DPEHPK3PXP - - WindowsHello - - Failed to init KeePassXC crypto. - - - - Failed to encrypt key data. - - - - Failed to get Windows Hello credential. - - - - Failed to decrypt key data. - - - YubiKey - - %1 No interface, slot %2 - - General: @@ -8961,14 +10313,6 @@ Exemplu: JBSWY3DPEHPK3PXP YubiKeyEditWidget - - Refresh hardware tokens - Actualizați jetoane hardware - - - Refresh - Actualizează - Hardware key slot selection Selectarea sloturilor pentru cheie hardware @@ -9001,10 +10345,6 @@ Exemplu: JBSWY3DPEHPK3PXP Challenge-Response set, click to change or remove - - <p>If you own a <a href="https://www.yubico.com/">YubiKey</a> or <a href="https://onlykey.io">OnlyKey</a>, you can use it for additional security.</p><p>The key requires one of its slots to be programmed as <a href="https://www.yubico.com/products/services-software/challenge-response/">HMAC-SHA1 Challenge-Response</a>.</p> - - Detecting hardware keys… @@ -9013,35 +10353,32 @@ Exemplu: JBSWY3DPEHPK3PXP No hardware keys detected - - - YubiKeyInterface - %1 Invalid slot specified - %2 + Refresh hardware keys + Reîmprospătarea tastelor hardware + + + <p>If you own a <a href="https://www.yubico.com/">YubiKey</a> or <a href="https://onlykey.io">OnlyKey</a>, you can use it for additional security.</p><p>The key requires one of its slots to be programmed with <a href="https://keepassxc.org/docs/#faq-yubikey-howto">Challenge-Response</a>.</p> + + + + Hardware keys found, but no slots are configured YubiKeyInterfacePCSC - - (PCSC) %1 [%2] Challenge-Response - Slot %3 - - The YubiKey PCSC interface has not been initialized. - - Hardware key is currently in use. - - Could not find or access hardware key with serial number %1. Please present it to continue. Hardware key is locked or timed out. Unlock or re-present it to continue. - + Cheia hardware este blocată sau a expirat. Deblocați-o sau prezentați-o din nou pentru a continua. Hardware key was not found or is not configured. @@ -9051,6 +10388,21 @@ Exemplu: JBSWY3DPEHPK3PXP Failed to complete a challenge-response, the PCSC error code was: %1 + + (NFC) %1 [%2] - Slot %3, %4 + YubiKey display fields + + + + Press + USB Challenge-Response Key interaction request + Apasă + + + Passive + USB Challenge-Response Key no interaction required + Pasiv + YubiKeyInterfaceUSB @@ -9058,14 +10410,6 @@ Exemplu: JBSWY3DPEHPK3PXP Unknown Necunoscut - - (USB) %1 [%2] Configured Slot - %3 - - - - (USB) %1 [%2] Challenge-Response - Slot %3 - %4 - - Press USB Challenge-Response Key interaction request @@ -9080,10 +10424,6 @@ Exemplu: JBSWY3DPEHPK3PXP The YubiKey USB interface has not been initialized. - - Hardware key is currently in use. - - Could not find hardware key with serial number %1. Please plug it in to continue. @@ -9100,5 +10440,15 @@ Exemplu: JBSWY3DPEHPK3PXP Failed to complete a challenge-response, the specific error was: %1 + + %1 [%2] - Slot %3 + YubiKey NEO display fields + + + + %1 [%2] - Slot %3, %4 + YubiKey display fields + + \ No newline at end of file diff --git a/share/translations/keepassxc_ru.ts b/share/translations/keepassxc_ru.ts index 320dc4b97..a6816c8c7 100644 --- a/share/translations/keepassxc_ru.ts +++ b/share/translations/keepassxc_ru.ts @@ -217,18 +217,50 @@ You must restart the application to set the new language. Would you like to restart now? Необходимо перезапустить приложение, чтобы установить новый язык. Перезапустить сейчас? - - Reset Settings? - Сбросить параметры? - - - Are you sure you want to reset all general and security settings to default? - Действительно сбросить все общие параметры и параметры безопасности к значениям, заданным по умолчанию? - Select backup storage directory Выбрать папку для резервной копии + + Confirm Reset + Подтвердить сброс + + + Are you sure you want to reset all settings to default? + Сбросить все параметры по умолчанию? + + + Import KeePassXC Settings + Импортировать настройки KeePassXC + + + Failed to import settings from %1, not a valid settings file. + Не удалось импортировать настройки из %1, не корректный файл настроек. + + + Export KeePassXC Settings + Экспортировать настройки KeePassXC + + + Small + Маленький + + + Normal + Обычный + + + Medium + Средний + + + Large + Большой + + + Custom + Пользовательский + ApplicationSettingsWidgetGeneral @@ -280,25 +312,6 @@ Include beta releases when checking for updates Включить в проверку обновлений бета-релизы - - On database unlock, show entries that - При разблокировке базы данных показывать записи, которые - - - have expired - On database unlock, show entries that... - истекли - - - days - On database unlock, show entries that will expire within %1 days - дней - - - will expire within - On database unlock, show entries that... - истекают в течение - File Management Управление файлами @@ -323,22 +336,10 @@ Backup database file before saving Создавать резервную копию базы данных перед сохранением - - Backup destination - Путь к резервной копии - - - Specifies the database backup file location. Occurrences of "{DB_FILENAME}" are replaced with the filename of the saved database without extension. {TIME:<format>} is replaced with the backup time, see https://doc.qt.io/qt-5/qdatetime.html#toString. <format> defaults to format string "dd_MM_yyyy_hh-mm-ss". - Указывает местоположение файла резервной копии базы данных. Встречающиеся «{DB_FILENAME}» заменяются именем файла сохранённой базы данных без расширения. {TIME:<format>} заменяется временем резервного копирования, см. https://doc.qt.io/qt-5/qdatetime.html#toString. <format> использует строку формата «дд_ММ_ггг_чч-мм-сс». - {DB_FILENAME}.old.kdbx {DB_FILENAME}.old.kdbx - - Choose... - Выбрать... - Use alternative saving method (may solve problems with Dropbox, Google Drive, GVFS, etc.) Использовать альтернативный метод хранения (может решить проблемы с Dropbox, Google Drive, GVFS и т.д.) @@ -505,6 +506,71 @@ Remember last typed entry for: Запомнить последнюю введённую запись для: + + On database unlock, show entries that will expire within + При разблокировке базы данных показать записи, срок действия которых истекает в течение + + + On database unlock, show entries that will expire within + При разблокировке базы данных показать записи, срок действия которых истекает в течение + + + days + number of days warning for password expiration + дн. + + + Destination format: + Формат назначения: + + + <html><head/><body><p><span style=" font-weight:600;">{DB_FILENAME}</span> is replaced with the filename of the saved database without extension</p><p><span style=" font-weight:600;">{TIME:&lt;format&gt;}</span> is replaced with the specified time format (default: dd_MM_yyyy_hh-mm-ss)</p><p>See the User Guide for more details</p></body></html> + <html><head/><body><p><span style=" font-weight:600;">{DB_FILENAME}</span>заменяется именем файла сохраненной базы данных без расширения</p><p><span style=" font-weight:600;">{TIME:&lt;format&gt;}</span>заменяется на указанный формат времени (по умолчанию: dd_MM_yyy_hh-mm-ss)</p><p>Подробнее см. в руководстве пользователя</p></body></html> + + + Choose folder... + Выбрать папку... + + + Show confirmation before moving entries to recycle bin + Показывать подтверждение перед перемещением записей в корзину + + + Copy data on double clicking field in entry view + Копировать данные при двойном щелчке на поле в режиме просмотра записи + + + Show toolbar + Отображать панель инструментов + + + Show the menu bar by pressing the Alt key + Отобразить меню при нажатии клавишу Alt + + + Show menubar + Отображать меню + + + Import settings… + Импортировать настройки... + + + Export settings… + Экспортировать настройки... + + + Open browser on double clicking URL field in entry view + Открывать URL-адрес в браузере при двойном щелчке по столбцу в режиме просмотра записей + + + Font size: + Размер шрифта: + + + Font size selection + Выбор размера шрифта + ApplicationSettingsWidgetSecurity @@ -570,18 +636,6 @@ Hide passwords in the entry preview panel Скрывать пароли в панели предварительного просмотра записи - - Hide entry notes by default - По умолчанию скрывать заметки к записи - - - Move entries to recycle bin without confirmation - Переместить записи в корзину без подтверждения - - - Enable double click to copy the username/password entry columns - Разрешить копирование столбцов записей имени пользователя и пароля по двойному щелчку - Privacy Конфиденциальность @@ -594,6 +648,18 @@ Hide TOTP in the entry preview panel Скрыть TOTP на панели предварительного просмотра записей + + Lock databases when switching user + Блокировать базы данных при переключении пользователя + + + Lock Options + Параметры блокировки + + + Hide notes in the entry preview panel + Скрыть заметки на панели предпросмотра + AutoType @@ -641,20 +707,6 @@ Entry does not have attribute for PICKCHARS: %1 Запись не имеет атрибута PICKCHARS: %1 - - Invalid conversion type: %1 - Недопустимый тип преобразования: %1 - - - Invalid conversion syntax: %1 - Недопустимый синтаксис преобразования: %1 - - - Invalid regular expression syntax %1 -%2 - Недопустимый синтаксис регулярного выражения %1 -%2 - Invalid placeholder: %1 Недопустимый заполнитель: %1 @@ -886,24 +938,25 @@ Please select the correct database for saving credentials. Add to existing entry - + Добавить к существующей записи Existing passkey found. Do you want to register a new passkey for: - + Существующий passkey найден. +Хотите зарегистрировать новый passkey для: Select the existing passkey and press Update to replace it. - + Выберите существующий passkey и нажмите Обновить, чтобы заменить его. Authenticate passkey credentials for: - + Аутентификация учетных данных passkey для: Do you want to register a passkey for: - + Вы хотите зарегистрировать passkey для: @@ -987,16 +1040,17 @@ Do you want to delete the entry? Register a new passkey to this entry: - + Зарегистрировать новый passkey для этой записи: KeePassXC - Update passkey - + KeePassXC - Обновить passkey Entry already has a passkey. Do you want to overwrite the passkey in %1 - %2? - + У записи уже есть passkey. +Хотите перезаписать passkey в %1 - %2? Register @@ -1021,10 +1075,6 @@ Do you want to overwrite the passkey in %1 - %2? General Общие - - Browsers installed as snaps are currently not supported. - Браузеры, установленные в виде snap-пакетов, в настоящее время не поддерживаются. - Enable integration for these browsers: Включить интеграцию для браузеров: @@ -1196,18 +1246,6 @@ Do you want to overwrite the passkey in %1 - %2? Custom extension ID Пользовательский идентификатор расширения - - Due to Snap sandboxing, you must run a script to enable browser integration.<br />You can obtain this script from %1 - Так как Snap это песочница, для включения браузерной интеграции нужно выполнить сценарий.<br />Этот сценарий можно получить с %1 - - - KeePassXC-Browser is needed for the browser integration to work. <br />Download it for %1 and %2 and %3. %4 - Для интеграции требуется установить расширение для браузера «KeePassXC-Browser». <br />Установите его для %1, %2 и %3. %4 - - - Please see special instructions for browser extension use below - Ознакомьтесь с инструкциями по использованию расширения браузера ниже - Executable Files Исполняемые файлы @@ -1250,11 +1288,19 @@ Do you want to overwrite the passkey in %1 - %2? Allows using insecure http://localhost with passkeys for testing purposes. - + Позволяет использовать небезопасный http://localhost с passkeys для тестирования. Allow using localhost with passkeys - + Разрешить использование localhost с passkeys + + + KeePassXC-Browser is needed for the browser integration to work. <br />Download it for %1 and %2 and %3. + Для интеграции с браузерами требуется KeePassXC-Browser. <br />Загрузите его для %1 и %2 и %3. + + + Browsers installed using Snap or Flatpak are not supported with exception to Firefox installed using Snap. + Браузеры, установленные с помощью Snap или Flatpak, не поддерживаются, за исключением Firefox, установленного с помощью Snap. @@ -1398,6 +1444,20 @@ Do you want to overwrite the passkey in %1 - %2? Imported from CSV file: %1 Импортировано из CSV-файла: %1 + + No Title Selected + Не выбрано название + + + No title column was selected, entries will be hard to tell apart. +Are you sure you want to import? + Не выбрано название столбца, записи будет трудно различить. +Хотите импортировать? + + + Tags + Теги + CsvParserModel @@ -1461,6 +1521,14 @@ Backup database located at %2 Recycle Bin Корзина + + Database file read error. + Ошибка чтения файла базы данных. + + + No file path was provided. + Не указан путь к файлу. + DatabaseOpenDialog @@ -1609,14 +1677,6 @@ To prevent this error from appearing, you must go to "Database Settings / S <p>In addition to a password, you can use a secret file to enhance the security of your database. This file can be generated in your database's security settings.</p><p>This is <strong>not</strong> your *.kdbx database file!</p> <p>Кроме пароля, вы можете использовать секретный файл для усиления безопасности вашей базы данных. Этот файл может быть сгенерирован в настройках безопасности вашей базы данных. </p><p>Это <strong>не</strong> ваш файл базы данных *.kdbx!</p> - - Click to add a key file. - Нажмите, чтобы добавить файл-ключ. - - - <a href="#" style="text-decoration: underline">I have a key file</a> - <a href="#" style="text-decoration: underline">У меня есть файл-ключ</a> - Use hardware key [Serial: %1] Использовать аппаратный ключ [Серийный номер: %1] @@ -1653,6 +1713,18 @@ Are you sure you want to continue with this file?. Refresh Hardware Keys Обновить аппаратные ключи + + Click to add a key file. + Нажмите, чтобы добавить файл-ключ. + + + <a href="#" style="text-decoration: underline">I have a key file</a> + <a href="#" style="text-decoration: underline">У меня есть файл-ключ</a> + + + Hardware keys found, but no slots are configured. + Аппаратные ключи найдены, но ни один слот не настроен. + DatabaseSettingWidgetMetaData @@ -1687,6 +1759,22 @@ Are you sure you want to continue with this file?. Maintenance Обслуживание + + KeeShare + KeeShare + + + Secret Service Integration + Интеграция с секретной службой + + + Remote Sync + Удалённая синхронизация + + + Database Settings: %1 + Параметры базы данных: %1 + DatabaseSettingsWidgetBrowser @@ -1857,14 +1945,14 @@ Are you sure you want to continue without a password? Weak password Слабый пароль - - You must enter a stronger password to protect your database. - Вам нужно ввести более надежный пароль для защиты вашей базы данных. - This is a weak password! For better protection of your secrets, you should choose a stronger password. Это слабый пароль! Для лучшей защиты ваших секретов вам следует выбрать более надежный пароль. + + The provided password does not meet the minimum quality requirement. + Предоставленный пароль не соответствует минимальным требованиям к качеству. + DatabaseSettingsWidgetEncryption @@ -2166,6 +2254,50 @@ removed from the database. Autosave delay since last change checkbox Задержка автосохранения с последнего изменения галочки + + Public Database Metadata + Метаданные публичной базы данных + + + Warning: the following settings are not encrypted. + Внимание: следующие параметры не зашифрованы. + + + Display name: + Отображаемое имя: + + + Publically visible display name used on the unlock dialog + Публичное отображаемое имя, используемое в диалоге разблокировки + + + Database public display name + Публичное имя базы данных + + + Display color: + Отображаемый цвет: + + + Publically visible color used on the unlock dialog + Публично видимый цвет, используемый в диалоге разблокировки + + + Database public display color chooser + Выбор цвета для публичного отображения базы данных + + + Clear + Очистить + + + Display icon: + Отображаемый значок: + + + Select Database Icon + Выбрать значок базы данных + DatabaseSettingsWidgetKeeShare @@ -2261,6 +2393,141 @@ removed from the database. Поле описания базы данных + + DatabaseSettingsWidgetRemote + + Sync Commands + Команды синхронизации + + + Remove + Удалить + + + Command Settings + Параметры команд + + + Name + Имя + + + Save + Сохранить + + + Download + Загрузить + + + Command: + Команда: + + + Download command field + Поле команды загрузки + + + e.g.: "sftp user@hostname" or "scp user@hostname:DatabaseOnRemote.kdbx {TEMP_DATABASE}" + Например: "sftp user@hostname" или "scp user@hostname:DatabaseOnRemote.kdbx {TEMP_DATABASE}" + + + Input: + Ввод: + + + Download input field + Поле ввода загрузки + + + Upload + Выгрузить + + + Upload command field + Поле команды выгрузки + + + e.g.: "sftp user@hostname" or "scp {TEMP_DATABASE} user@hostname:DatabaseOnRemote.kdbx" + Например: "sftp user@hostname" или "scp {TEMP_DATABASE} user@hostname:DatabaseOnRemote.kdbx" + + + Upload input field + Поле команды выгрузки + + + Name cannot be empty. + Имя не может быть пустым. + + + Test + Тест + + + Download command cannot be empty. + Команда загрузки не может быть пустой. + + + Download failed with error: %1 + Загрузка завершилась с ошибкой: %1 + + + Download finished, but file %1 could not be found. + Загрузка завершена, но файл %1 не найден. + + + Download successful. + Загрузка завершена. + + + Save Remote Settings + Сохранить удаленные параметры + + + You have unsaved changes. Do you want to save them? + У вас есть несохраненные изменения. Хотите сохранить их? + + + e.g.: +get DatabaseOnRemote.kdbx {TEMP_DATABASE} +exit +--- +{TEMP_DATABASE} is used as placeholder to store the database in a temporary location +The command has to exit. In case of `sftp` as last command `exit` has to be sent + + Например: +get DatabaseOnRemote.kdbx {TEMP_DATABASE} +exit +--- +{TEMP_DATABASE} используется в качестве заполнителя для хранения базы данных во временном месте. +Команда должна завершиться. В случае с `sftp` в качестве последней команды необходимо отправить `exit`. + + + + e.g.: +put {TEMP_DATABASE} DatabaseOnRemote.kdbx +exit +--- +{TEMP_DATABASE} is used as placeholder to store the database in a temporary location +The command has to exit. In case of `sftp` as last command `exit` has to be sent + + Например: +put {TEMP_DATABASE} DatabaseOnRemote.kdbx +exit +--- +{TEMP_DATABASE} используется в качестве заполнителя для хранения базы данных во временном месте. +Команда должна завершиться. В случае с `sftp` в качестве последней команды необходимо отправить `exit`. + + + + Timeout: + Таймаут: + + + seconds + сек + + DatabaseTabWidget @@ -2334,6 +2601,11 @@ This is definitely a bug, please report it to the developers. Database tab name modifier %1 [заблокировано] + + %1 [Temporary] + Database tab name modifier + %1 [Временный] + DatabaseWidget @@ -2457,26 +2729,6 @@ Save changes? File has changed Файл изменён - - The database file has changed. Do you want to load the changes? - Файл базы данных был изменён. Загрузить изменения? - - - Merge Request - Запрос на слияние - - - The database file has changed and you have unsaved changes. -Do you want to merge your changes? - База данных была изменена, есть несохранённые изменения. -Объединить изменения? - - - Could not open the new database file while attempting to autoreload. -Error: %1 - Не удалось открыть новый файл базы данных при попытке автоматически загрузить повторно. -Ошибка: %1 - Disable safe saves? Отключить безопасное сохранение? @@ -2528,6 +2780,86 @@ Disable safe saves and try again? Database tab name modifier %1 [новая база данных] + + Remote Sync did not contain any download or upload commands. + Удаленная синхронизация не содержала команд загрузки или выгрузки. + + + Remote sync '%1' completed successfully! + Удаленная синхронизация '%1' успешно завершена! + + + Remote sync '%1' failed: %2 + Удаленная синхронизация '%1' не удалась: %2 + + + Error while saving database %1: %2 + Ошибка при сохранении базы данных %1: %2 + + + Downloading... + Загрузка... + + + Uploading... + Выгрузка... + + + Syncing... + Синхронизация... + + + Remove passkey from entry + Удалить passkey из записи + + + Do you want to remove the passkey from this entry? + Удалить passkey из этой записи? + + + The database file "%1" was modified externally + Файл базы данных "%1" был изменен извне + + + Do you want to load the changes? + Вы хотите загрузить изменения? + + + Reload database + Перезагрузить базу данных + + + Reloading database… + Перезагрузка базы данных... + + + Reload canceled + Перезагрузка отменена + + + Reload successful + Перезагрузка завершена + + + Reload pending user action… + Перезагрузка в ожидании действия пользователя... + + + The database file "%1" was modified externally.<br>How would you like to proceed?<br><br>Merge all changes<br>Ignore the changes on disk until save<br>Discard unsaved changes + Файл базы данных "%1" был изменен извне.<br>Как вы хотите поступить?<br><br>Объединить все изменения<br>Игнорировать изменения на диске до сохранения<br>Отменить несохраненные изменения + + + The database file "%1" was modified externally.<br>How would you like to proceed?<br><br>Merge all changes then save<br>Overwrite the changes on disk<br>Discard unsaved changes + Файл базы данных "%1" был изменен извне.<br>Как вы хотите поступить?<br><br>Объединить все изменения и сохранить<br>Перезаписать изменения на диске<br>Отменить несохраненные изменения + + + Database file overwritten. + Файл базы данных перезаписан. + + + Database file on disk cannot be unlocked with current credentials.<br>Enter new credentials and/or present hardware key to continue. + Файл базы данных на диске не может быть разблокирован с текущими учетными данными.<br>Введите новые учетные данные и/или используйте аппаратный ключ для продолжения. + EditEntryWidget @@ -2579,10 +2911,6 @@ Disable safe saves and try again? n/a н/д - - (encrypted) - (зашифровано) - Select private key Выберите закрытый (личный) ключ @@ -2684,6 +3012,10 @@ Would you like to correct it? %n year(s) %n год%n лет%n лет%n лет + + Failed to decrypt SSH key, ensure password is correct. + Не удалось расшифровать ключ SSH, проверьте правильность пароля. + EditEntryWidgetAdvanced @@ -2855,18 +3187,10 @@ Would you like to correct it? Skip Auto-Submit for this entry Не использовать автоматическую отправку данных форм для этой записи - - Only send this setting to the browser for HTTP Auth dialogs. If enabled, normal login forms will not show this entry for selection. - Отправлять эту настройку только браузерным диалогам для диалогов HTTP Auth. Если включено, обычные формы авторизации не покажут запись среди вариантов выбора. - Use this entry only with HTTP Basic Auth Использовать эту запись только при обычной проверке подлинности HTTP - - Do not send this setting to the browser for HTTP Auth dialogs. If enabled, HTTP Auth dialogs will not show this entry for selection. - Не отправлять эту настройку в браузер для диалогов HTTP Auth. Если включено, данные диалоги не покажутся для этой записи для выбора. - Do not use this entry with HTTP Basic Auth Не использовать эту запись для базовой HTTP-авторизации @@ -2891,6 +3215,14 @@ Would you like to correct it? Additional URLs Дополнительные URL-адреса + + Only send this entry to the browser for HTTP Auth dialogs. If enabled, normal login forms will not show this entry for selection. + Отправлять эту запись только браузерным диалогам HTTP Auth. Если включено, обычные формы авторизации не покажут запись среди вариантов выбора. + + + Do not send this entry to the browser for HTTP Auth dialogs. If enabled, HTTP Auth dialogs will not show this entry for selection. + Не отправлять эту запись браузерным диалогам HTTP Auth. Если включено, в этих диалогах не будет выбора данной записи. + EditEntryWidgetHistory @@ -3113,6 +3445,10 @@ Would you like to correct it? seconds с + + Clear agent + Очистить агент + EditGroupWidget @@ -3555,12 +3891,45 @@ This may cause the affected plugins to malfunction. %1 - Clone %1 — клон + + Passkey + Passkey + + + Invalid conversion type: %1 + Недопустимый тип преобразования: %1 + + + Invalid conversion syntax: %1 + Недопустимый синтаксис преобразования: %1 + + + Invalid regular expression syntax %1 +%2 + Недопустимый синтаксис регулярного выражения %1 +%2 + EntryAttachments Cannot open file "%1" - Не удалось открыть файл «%1» + Не удалось открыть файл "%1" + + + + EntryAttachmentsDialog + + Form + Форма + + + File name + Имя файла + + + File contents... + Содержимое файла... @@ -3600,14 +3969,6 @@ This may cause the affected plugins to malfunction. Remove Удалить - - Rename selected attachment - Переименовать выбранное вложение - - - Rename - Переименовать - Open selected attachment Открыть выбранное вложение @@ -3725,6 +4086,18 @@ Would you like to overwrite the existing attachment? Вложение «%1» уже существует. Перезаписать существующее вложение? + + New + Новый + + + Preview + Просмотр + + + Failed to preview an attachment: Attachment not found + Не удалось просмотреть вложение: Вложение не найдено + EntryAttributesModel @@ -3923,6 +4296,10 @@ Would you like to overwrite the existing attachment? Background Color Цвет фона + + Group Path + Путь группы + EntryPreviewWidget @@ -4317,6 +4694,14 @@ You can enable the DuckDuckGo website icon service in the security section of th Url URL-адрес + + Could not load key file. + Не удалось загрузить файл-ключ. + + + Could not open remote database. Password or key file may be incorrect. + Не удалось открыть удаленную базу данных. Пароль или файл-ключ могут быть неверными. + ImportWizardPageSelect @@ -4420,6 +4805,50 @@ You can enable the DuckDuckGo website icon service in the security section of th KeePass1 Database База данных KeePass1 + + Proton Pass (.json) + Proton Pass (.json) + + + Proton Pass JSON Export + Экспорт из Proton Pass в JSON + + + Temporary Database + Временная база данных + + + Command: + Команда: + + + e.g.: "sftp user@hostname" or "scp user@hostname:DatabaseOnRemote.kdbx {TEMP_DATABASE}" + Например: "sftp user@hostname" или "scp user@hostname:DatabaseOnRemote.kdbx {TEMP_DATABASE}" + + + Input: + Ввод: + + + e.g.: +get DatabaseOnRemote.kdbx {TEMP_DATABASE} +exit +--- +{TEMP_DATABASE} is used as placeholder to store the database in a temporary location +The command has to exit. In case of `sftp` as last commend `exit` has to be sent + + Например: +get DatabaseOnRemote.kdbx {TEMP_DATABASE} +exit +--- +{TEMP_DATABASE} используется в качестве заполнителя для хранения базы данных во временном месте. +Команда должна завершиться. В случае с `sftp` в качестве последней команды необходимо отправить `exit`. + + + + Remote Database (.kdbx) + Удалённая база данных (.kdbx) + KMessageWidget @@ -5510,11 +5939,11 @@ Are you sure you want to continue with this file? Show Toolbar - Показать панель инструментов + Отображать панель инструментов Show Preview Panel - Показать панель предварительного просмотра + Отображать панель предпросмотра Always on Top @@ -5561,12 +5990,6 @@ This version is not meant for production use. Expect some bugs and minor issues, this version is meant for testing purposes. ВНИМАНИЕ: вы используете бета-версию KeePassXC! В ней возможны ошибки и небольшие проблемы, она предназначена для тестирования. - - - WARNING: Your Qt version may cause KeePassXC to crash with an On-Screen Keyboard. -We recommend you use the AppImage available on our downloads page. - ВНИМАНИЕ: ваша версия Qt может привести к сбоям KeePassXC при работе с экранной клавиатурой. -Рекомендуется использовать AppImage с нашей страницы загрузок. No Tags @@ -5640,6 +6063,10 @@ We recommend you use the AppImage available on our downloads page. Import Passkey Импорт Passkey + + Remote S&ync… + Удаленная с&инхронизация… + Quit Application Закрыть приложение @@ -5744,6 +6171,10 @@ We recommend you use the AppImage available on our downloads page. Show Password Generator Открыть генератор паролей + + Remove Passkey From Entry + Удалить passkey из записи + Perform Auto-Type: {USERNAME} Автоматический ввод: {USERNAME} @@ -5888,6 +6319,34 @@ We recommend you use the AppImage available on our downloads page. Toggle Allow Screen Capture Разрешить скриншоты + + Show Group Panel + Отображать панель групп + + + Toggle Show Group Panel + Отображать панель групп + + + Setup Remote Sync… + Настройка удаленной синхронизации… + + + Password Generator + Генератор паролей + + + E&xpire Entry… + И&стекает запись... + + + Clear SSH Agent + Очистить SSH-агент + + + Clear all identities in ssh-agent + Очистить все идентификаторы в ssh-агенте + ManageDatabase @@ -6038,6 +6497,25 @@ We recommend you use the AppImage available on our downloads page. Заполните отображаемое имя и, при желании, описание новой базы данных: + + NewEntryAttachmentsDialog + + Attachment name cannot be empty + Имя вложения не может быть пустым + + + Attachment with the same name already exists + Вложение с таким же именем уже существует + + + Save attachment + Сохранить вложение + + + New entry attachment + Новое вложение записи + + NixUtils @@ -6225,6 +6703,10 @@ We recommend you use the AppImage available on our downloads page. Unexpected EOF when writing private key Неожиданный конец файла при записи закрытого (личного) ключа + + (encrypted) + (зашифровано) + OpenSSHKeyGenDialog @@ -6273,7 +6755,7 @@ We recommend you use the AppImage available on our downloads page. Export the following passkey entries. - + Экспортировать следующие записи passkey. @@ -6347,15 +6829,15 @@ Do you want to overwrite it? Import the following passkey: - + Импортировать следующий passkey: Import the following passkey to this entry: - + Импортировать следующий passkey в эту запись: Default passkeys group (Imported Passkeys) - + Группа passkeys по умолчанию (Импортированные Passkeys) @@ -6378,25 +6860,27 @@ Do you want to overwrite it? Open passkey file - + Открыть passkey файл Cannot import passkey - + Не удаётся импортировать passkey Cannot import passkey file "%1". Data is missing. - + Не удаётся импортировать passkey файл "%1". Данные отсутствуют. Cannot import passkey file "%1". The following data is missing: %2 - + Не удаётся импортировать passkey файл "%1". +Следующие данные отсутствуют: +%2 Cannot import passkey file "%1". Private key is missing or malformed. - + Не удаётся импортировать passkey файл "%1". Приватный ключ отсутствует или поврежден. @@ -6577,10 +7061,6 @@ The following data is missing: Also choose from: Дополнительные символы: - - Excluded characters: "0", "1", "l", "I", "O", "|", "﹒" - Исключить символы: «0», «1», «l», «I», «O», «|», «﹒» - Exclude look-alike characters Не использовать визуально схожие символы @@ -6605,10 +7085,6 @@ The following data is missing: Word Count: Количество слов: - - Character Count: - Количество символов: - Word Case: Регистр слов: @@ -6621,10 +7097,6 @@ The following data is missing: Add custom wordlist Добавить свой словарь - - character - символ - Close Закрыть @@ -6731,6 +7203,22 @@ Do you want to overwrite it? Special Characters Специальные символы + + passwordLength + Длина пароля + + + Characters: %1 + Символы: %1 + + + MIXED case + СМЕШАННЫЙ регистр + + + Excluded characters: "0", "1", "l", "I", "O", "|", "﹒", "B", "8", "G", "6" + Исключить символы: "0", "1", "l", "I", "O", "|", "﹒", "B", "8", "G", "6" + PasswordWidget @@ -6798,6 +7286,21 @@ Do you want to overwrite it? Нажимать &Tab между символами + + PreviewEntryAttachmentsDialog + + Preview entry attachment + Предварительный просмотр вложения записи + + + No preview available + Предварительный просмотр недоступен + + + Image format not supported + Формат изображения не поддерживается + + QMessageBox @@ -7476,10 +7979,6 @@ Do you want to overwrite it? Invalid word count %1 Количество неверных слов: %1 - - The word list is too small (< 1000 items) - Словарь слишком маленький (< 1000 слов) - Title for the entry. Название записи. @@ -7624,10 +8123,6 @@ Do you want to overwrite it? Exit interactive mode. Покинуть интерактивный режим. - - Format to use when exporting. Available choices are 'xml' or 'csv'. Defaults to 'xml'. - Выбор формата файла для экспорта. Возможные варианты: XML (по умолчанию) или CSV. - Exports the content of a database to standard output in the specified format. Экспорт базы данных в заданном формате на устройство стандартного вывода. @@ -8216,18 +8711,6 @@ Kernel: %3 %4 file empty пустой файл - - malformed string - неправильная строка - - - missing closing quote - отсутствует закрывающая кавычка - - - %1: (row, col) %2,%3 - %1: (строка, столбец) %2,%3 - AES 256-bit AES 256 бит @@ -8673,12 +9156,88 @@ This option is deprecated, use --set-key-file instead. Комбинации клавиш - Unsupported KDF type, cannot decrypt json file - Неподдерживаемый тип KDF, не удаётся расшифровать json-файл + Unknown passkeys error + Неизвестная ошибка passkeys - Unknown passkeys error - + Invalid KDF iterations, cannot decrypt json file + Недопустимые итерации KDF, невозможно расшифровать json-файл + + + Unsupported format, ensure your Bitwarden export is password-protected + Неподдерживаемый формат. Убедитесь, что экспорт Bitwarden защищен паролем + + + Only PBKDF and Argon2 are supported, cannot decrypt json file + Поддерживаются только PBKDF и Argon2, невозможно расшифровать json-файл + + + Reset Shortcuts + Сброс комбинаций + + + Double click an action to change its shortcut + Дважды щелкните по действию, чтобы изменить его комбинацию + + + Filter... + Фильтр... + + + Shortcut Conflict + Конфликт комбинации + + + Shortcut %1 conflicts with '%2'. Overwrite shortcut? + Комбинация клавиш %1 конфликтует с '%2'. Перезаписать комбинацию? + + + Cannot generate valid passphrases because the wordlist is too short + Не удалось создать правильную парольную фразу, список слов слишком короткий + + + Encrypted files are not supported. + Зашифрованные файлы не поддерживаются. + + + Proton Pass Import + Импорт из Proton Pass + + + Delete plugin data? + Удалить данные модулей? + + + Delete plugin data from Entry(s)? + Удалить данные плагина из записи?Удалить данные плагина из записей?Удалить данные плагина из записей?Удалить данные плагина из записей? + + + Passkey + Ключ доступа + + + Format to use when exporting. Available choices are 'xml', 'csv' or 'html'. Defaults to 'xml'. + Формат, который будет использоваться при экспорте. Доступны следующие варианты: 'xml', 'csv' или 'html'. По умолчанию используется 'xml'. + + + start minimized to the system tray + запустить скрыв в системном трее + + + malformed string, possible unescaped delimiter + некорректная строка, возможно, неэкранированный разделитель + + + missing closing delimiter + отсутствует закрывающий разделитель + + + %1, row: %2, column: %3 + %1, строка: %2, столбец: %3 + + + Tags + Теги @@ -8715,6 +9274,37 @@ This option is deprecated, use --set-key-file instead. Внутренняя ошибка zlib: + + RemoteHandler + + Command `%1` did not finish in time. Process was killed. + Команда `%1` не завершилась вовремя. Процесс был завершен. + + + Failed to upload merged database. Command `%1` did not finish in time. Process was killed. + Не удалось загрузить объединенную базу данных. Команда `%1` не завершилась вовремя. Процесс был завершен. + + + Invalid download parameters provided. + Указаны недопустимые параметры загрузки. + + + Command `%1` failed to download database. + Команде `%1` не удалось загрузить базу данных. + + + Invalid database pointer or upload parameters provided. + Неверный указатель базы данных или указанные параметры выгрузки. + + + Command `%1` exited with status code: %2 + Команда `%1` завершилась с кодом состояния: %2 + + + Failed to upload merged database. Command `%1` exited with status code: %2 + Не удалось загрузить объединенную базу данных. Команда `%1` завершилась с кодом состояния: %2 + + ReportsWidgetBrowserStatistics @@ -8781,6 +9371,10 @@ This option is deprecated, use --set-key-file instead. Exclude from reports Исключить из отчётов + + Expire Entry(s)… + Истекает запись...Истекают записи...Истекает записей...Истекает записей... + Only show entries that have a URL Показывать только записи с URL-адресом @@ -8797,36 +9391,33 @@ This option is deprecated, use --set-key-file instead. (Expired) (Истекший) + + Delete plugin data from Entry(s)… + Удалить данные плагина из записи...Удалить данные плагина из записей..Удалить данные плагина из записей..Удалить данные плагина из записей.. + ReportsWidgetHealthcheck - Hover over reason to show additional details. Double-click entries to edit. - Наведите курсор, чтобы просмотреть дополнительные сведения. Для редактирования записи дважды щёлкните левой кнопкой мыши. + Show expired entries + Показать просроченные записи - Bad - Password quality - Плохой + (Expired) + (Истекший) + + + Hover over reason to show additional details. Double-click entries to edit. + Наведите курсор, чтобы просмотреть дополнительные сведения. Для редактирования записи дважды щёлкните левой кнопкой мыши. Bad — password must be changed Плохой — пароль должен быть изменён - - Poor - Password quality - Слабый - Poor — password should be changed Слабый — пароль следует изменить - - Weak - Password quality - Очень слабый - Weak — consider changing the password Очень слабый — пароль желательно изменить @@ -8875,18 +9466,14 @@ This option is deprecated, use --set-key-file instead. Exclude from reports Исключить из отчётов - - Show expired entries - Показать просроченные записи + + Expire Entry(s)… + Истекает запись...Истекают записи...Истекает записей...Истекает записей... Show entries that have been excluded from reports Показать записи, которые были исключены из отчетов - - (Expired) - (Истекший) - ReportsWidgetHibp @@ -8982,6 +9569,10 @@ This option is deprecated, use --set-key-file instead. Exclude from reports Исключить из отчётов + + Expire Entry(s)… + Истекает запись...Истекают записи...Истекает записей...Истекает записей... + ReportsWidgetPasskeys @@ -9043,11 +9634,11 @@ This option is deprecated, use --set-key-file instead. Please wait, list of entries with passkeys is being updated… - + Пожалуйста, подождите, список записей с passkeys обновляется... No entries with passkeys. - + Нет записей c passkeys. @@ -9223,6 +9814,14 @@ This option is deprecated, use --set-key-file instead. No agent running, cannot list identities. Агент не запущен, идентификационные данные недоступны. + + Failed to remove all SSH identities from agent. + Ошибка при удалении всех SSH-идентификаторов из агента + + + All SSH identities removed from agent. + Все SSH-идентификаторы удалены из агента. + SearchHelpWidget @@ -9508,29 +10107,6 @@ This option is deprecated, use --set-key-file instead. Экспорт в %1 - - ShortcutSettingsWidget - - Double click an action to change its shortcut - Дважды щелкните по действию, чтобы изменить его комбинацию - - - Shortcut Conflict - Конфликт комбинации - - - Filter... - Фильтр... - - - Shortcut %1 conflicts with '%2'. Overwrite shortcut? - Комбинация клавиш %1 конфликтует с '%2'. Перезаписать комбинацию? - - - Reset Shortcuts - Сброс комбинаций - - TagModel @@ -9818,14 +10394,18 @@ Example: JBSWY3DPEHPK3PXP No hardware keys detected Аппаратные ключи не обнаружены - - <p>If you own a <a href="https://www.yubico.com/">YubiKey</a> or <a href="https://onlykey.io">OnlyKey</a>, you can use it for additional security.</p><p>The key requires one of its slots to be programmed as <a href="https://docs.yubico.com/yesdk/users-manual/application-otp/challenge-response.html">HMAC-SHA1 Challenge-Response</a>.</p> - <p>Если у вас есть <a href="https://www.yubico.com/">YubiKey</a> или <a href="https://onlykey.io">OnlyKey</a>, его можно использовать для дополнительной безопасности.</p><p>Для работы ключа необходимо, чтобы один из его слотов был запрограммирован как <a href="https://docs.yubico.com/yesdk/users-manual/application-otp/challenge-response.html">вызов-ответ HMAC-SHA1</a>.</p> - Refresh hardware keys Обновить аппаратные ключи + + <p>If you own a <a href="https://www.yubico.com/">YubiKey</a> or <a href="https://onlykey.io">OnlyKey</a>, you can use it for additional security.</p><p>The key requires one of its slots to be programmed with <a href="https://keepassxc.org/docs/#faq-yubikey-howto">Challenge-Response</a>.</p> + <p>Если у вас есть <a href="https://www.yubico.com/">YubiKey</a> или <a href="https://onlykey.io">OnlyKey</a>, его можно использовать как дополнительную защиту.</p><p>Для работы ключа необходимо, чтобы один из его слотов был запрограммирован как <a href="https://keepassxc.org/docs/#faq-yubikey-howto">вызов-ответ</a>.</p> + + + Hardware keys found, but no slots are configured + Аппаратные ключи найдены, но ни один слот не настроен. + YubiKeyInterfacePCSC diff --git a/share/translations/keepassxc_si.ts b/share/translations/keepassxc_si.ts index 51362562d..ed896116f 100644 --- a/share/translations/keepassxc_si.ts +++ b/share/translations/keepassxc_si.ts @@ -217,18 +217,50 @@ You must restart the application to set the new language. Would you like to restart now? නව භාෂාව සැකසීමට ඔබ යෙදුම නැවත ආරම්භ කළ යුතුය. ඔබ දැන් නැවත ආරම්භ කිරීමට කැමතිද? - - Reset Settings? - සැකසුම් යළි සකසන්නද? - - - Are you sure you want to reset all general and security settings to default? - ඔබට සියලු සාමාන්‍ය සහ ආරක්‍ෂක සැකසුම් පෙරනිමියට යළි පිහිටුවීමට අවශ්‍ය බව විශ්වාසද? - Select backup storage directory උපස්ථ ගබඩා නාමාවලිය තෝරන්න + + Confirm Reset + + + + Are you sure you want to reset all settings to default? + + + + Import KeePassXC Settings + + + + Failed to import settings from %1, not a valid settings file. + + + + Export KeePassXC Settings + + + + Small + + + + Normal + + + + Medium + + + + Large + + + + Custom + + ApplicationSettingsWidgetGeneral @@ -280,25 +312,6 @@ Include beta releases when checking for updates යාවත්කාලීන සඳහා පරීක්ෂා කිරීමේදී බීටා නිකුතු ඇතුළත් කරන්න - - On database unlock, show entries that - දත්ත සමුදාය අගුළු හැරීමේදී, එම ඇතුළත් කිරීම් පෙන්වන්න - - - have expired - On database unlock, show entries that... - ඉකුත් වී ඇත - - - days - On database unlock, show entries that will expire within %1 days - දවස් - - - will expire within - On database unlock, show entries that... - ඉකුත් වීම - File Management ගොනු කළමනාකරණය @@ -323,22 +336,10 @@ Backup database file before saving සුරැකීමට පෙර දත්තසමුදාය උපස්ථ කරන්න - - Backup destination - උපස්ථ ස්ථානය - - - Specifies the database backup file location. Occurrences of "{DB_FILENAME}" are replaced with the filename of the saved database without extension. {TIME:<format>} is replaced with the backup time, see https://doc.qt.io/qt-5/qdatetime.html#toString. <format> defaults to format string "dd_MM_yyyy_hh-mm-ss". - දත්ත සමුදා උපස්ථ ගොනු ස්ථානය සඳහන් කරයි. "{DB_FILENAME}" සිදුවීම් දිගුවකින් තොරව සුරකින ලද දත්ත සමුදායේ ගොනු නාමයෙන් ප්‍රතිස්ථාපනය වේ. {TIME:<format>} උපස්ථ කාලය සමඟ ප්‍රතිස්ථාපනය වේ, https://doc.qt.io/qt-5/qdatetime.html#toString බලන්න. පෙළ "dd_MM_yyyy_hh-mm-ss"ආකෘතිකරණය කිරීමට පෙරනිමි <format> ක්. - {DB_FILENAME}.old.kdbx {DB_FILENAME}.old.kdbx - - Choose... - තෝරන්න... - Use alternative saving method (may solve problems with Dropbox, Google Drive, GVFS, etc.) විකල්ප ඉතිරි කිරීමේ ක්‍රමයක් භාවිතා කරන්න (ඩ්‍රොප්බොක්ස්, ගූගල් ඩ්‍රයිව්, ජීවීඑෆ්එස්, ආදිය සමඟ ගැටලු විසඳා ගත හැක) @@ -505,6 +506,71 @@ Remember last typed entry for: අවසන් වරට ටයිප් කළ ප්‍රවේශය මතක තබා ගන්න: + + On database unlock, show entries that will expire within + + + + On database unlock, show entries that will expire within + + + + days + number of days warning for password expiration + දවස් + + + Destination format: + + + + <html><head/><body><p><span style=" font-weight:600;">{DB_FILENAME}</span> is replaced with the filename of the saved database without extension</p><p><span style=" font-weight:600;">{TIME:&lt;format&gt;}</span> is replaced with the specified time format (default: dd_MM_yyyy_hh-mm-ss)</p><p>See the User Guide for more details</p></body></html> + + + + Choose folder... + + + + Show confirmation before moving entries to recycle bin + + + + Copy data on double clicking field in entry view + + + + Show toolbar + + + + Show the menu bar by pressing the Alt key + + + + Show menubar + + + + Import settings… + + + + Export settings… + + + + Open browser on double clicking URL field in entry view + + + + Font size: + + + + Font size selection + + ApplicationSettingsWidgetSecurity @@ -570,18 +636,6 @@ Hide passwords in the entry preview panel ඇතුල්වීමේ පෙරදසුන් පැනලයේ මුරපද සඟවන්න - - Hide entry notes by default - ප්‍රවේශ සටහන් පෙරනිමියෙන් සඟවන්න - - - Move entries to recycle bin without confirmation - තහවුරු කිරීමකින් තොරව ඇතුළත් කිරීම් ප්‍රතිචක්‍රීකරණ බඳුනට ගෙන යන්න - - - Enable double click to copy the username/password entry columns - පරිශීලක නාමය/මුරපද ඇතුළත් කිරීමේ තීරු පිටපත් කිරීමට ද්විත්ව ක්ලික් කිරීම සබල කරන්න - Privacy රහස්‍යතාව @@ -594,6 +648,18 @@ Hide TOTP in the entry preview panel + + Lock databases when switching user + + + + Lock Options + + + + Hide notes in the entry preview panel + + AutoType @@ -641,20 +707,6 @@ Entry does not have attribute for PICKCHARS: %1 ප්‍රවේශයට PICKCHARS සඳහා ගුණාංග නොමැත: %1 - - Invalid conversion type: %1 - වලංගු නොවන පරිවර්තන වර්ගය: %1 - - - Invalid conversion syntax: %1 - අවලංගු පරිවර්තන වාක්‍ය ඛණ්ඩය: %1 - - - Invalid regular expression syntax %1 -%2 - වලංගු නොවන නිත්‍ය ප්‍රකාශන වාක්‍ය ඛණ්ඩ %1 -%2 - Invalid placeholder: %1 වලංගු නොවන ස්ථාන දරණ: %1 @@ -1022,10 +1074,6 @@ Do you want to overwrite the passkey in %1 - %2? General සාමාන්‍ය - - Browsers installed as snaps are currently not supported. - ස්නැප් ලෙස ස්ථාපනය කර ඇති බ්‍රව්සර් දැනට සහය නොදක්වයි. - Enable integration for these browsers: මෙම බ්‍රව්සර් සඳහා ඒකාබද්ධ කිරීම සබල කරන්න: @@ -1197,18 +1245,6 @@ Do you want to overwrite the passkey in %1 - %2? Custom extension ID අභිරුචි දිගු ID - - Due to Snap sandboxing, you must run a script to enable browser integration.<br />You can obtain this script from %1 - Snap sandboxing හේතුවෙන්, ඔබ බ්‍රවුසර ඒකාබද්ධ කිරීම සබල කිරීමට ස්ක්‍රිප්ට් එකක් ධාවනය කළ යුතුය.<br />ඔබට මෙම ස්ක්‍රිප්ට් එක %1වෙතින් ලබාගත හැක - - - KeePassXC-Browser is needed for the browser integration to work. <br />Download it for %1 and %2 and %3. %4 - KeePassXC-Browser ක්‍රියා කිරීමට බ්‍රවුසර ඒකාබද්ධ කිරීම සඳහා අවශ්‍ය වේ. <br />එය %1 සහ %2 සහ %3සඳහා බාගන්න. %4 - - - Please see special instructions for browser extension use below - කරුණාකර පහත බ්‍රවුසර දිගු භාවිතය සඳහා විශේෂ උපදෙස් බලන්න - Executable Files ක්‍රියාත්මක කළ හැකි ගොනු @@ -1257,6 +1293,14 @@ Do you want to overwrite the passkey in %1 - %2? Allow using localhost with passkeys + + KeePassXC-Browser is needed for the browser integration to work. <br />Download it for %1 and %2 and %3. + + + + Browsers installed using Snap or Flatpak are not supported with exception to Firefox installed using Snap. + + CloneDialog @@ -1399,6 +1443,19 @@ Do you want to overwrite the passkey in %1 - %2? Imported from CSV file: %1 + + No Title Selected + + + + No title column was selected, entries will be hard to tell apart. +Are you sure you want to import? + + + + Tags + අනන්‍යන + CsvParserModel @@ -1462,6 +1519,14 @@ Backup database located at %2 Recycle Bin ප්‍රතිචක්‍රීකරණ බඳුන + + Database file read error. + + + + No file path was provided. + + DatabaseOpenDialog @@ -1610,14 +1675,6 @@ To prevent this error from appearing, you must go to "Database Settings / S <p>In addition to a password, you can use a secret file to enhance the security of your database. This file can be generated in your database's security settings.</p><p>This is <strong>not</strong> your *.kdbx database file!</p> - - Click to add a key file. - - - - <a href="#" style="text-decoration: underline">I have a key file</a> - - Use hardware key [Serial: %1] @@ -1650,6 +1707,18 @@ Are you sure you want to continue with this file?. Refresh Hardware Keys + + Click to add a key file. + + + + <a href="#" style="text-decoration: underline">I have a key file</a> + + + + Hardware keys found, but no slots are configured. + + DatabaseSettingWidgetMetaData @@ -1684,6 +1753,22 @@ Are you sure you want to continue with this file?. Maintenance නඩත්තු + + KeeShare + KeeShare + + + Secret Service Integration + රහස් සේවා ඒකාබද්ධ කිරීම + + + Remote Sync + + + + Database Settings: %1 + + DatabaseSettingsWidgetBrowser @@ -1855,11 +1940,11 @@ Are you sure you want to continue without a password? දුර්වල මුරපදය - You must enter a stronger password to protect your database. + This is a weak password! For better protection of your secrets, you should choose a stronger password. - This is a weak password! For better protection of your secrets, you should choose a stronger password. + The provided password does not meet the minimum quality requirement. @@ -2154,6 +2239,50 @@ removed from the database. Autosave delay since last change checkbox + + Public Database Metadata + + + + Warning: the following settings are not encrypted. + + + + Display name: + + + + Publically visible display name used on the unlock dialog + + + + Database public display name + + + + Display color: + + + + Publically visible color used on the unlock dialog + + + + Database public display color chooser + + + + Clear + පැහැදිලිව + + + Display icon: + + + + Select Database Icon + + DatabaseSettingsWidgetKeeShare @@ -2249,6 +2378,129 @@ removed from the database. දත්තසමුදායේ විස්තර ක්‍ෂේත්‍රය + + DatabaseSettingsWidgetRemote + + Sync Commands + + + + Remove + ඉවතලන්න + + + Command Settings + + + + Name + නම + + + Save + සුරකින්න + + + Download + + + + Command: + + + + Download command field + + + + e.g.: "sftp user@hostname" or "scp user@hostname:DatabaseOnRemote.kdbx {TEMP_DATABASE}" + + + + Input: + + + + Download input field + + + + Upload + + + + Upload command field + + + + e.g.: "sftp user@hostname" or "scp {TEMP_DATABASE} user@hostname:DatabaseOnRemote.kdbx" + + + + Upload input field + + + + Name cannot be empty. + + + + Test + + + + Download command cannot be empty. + + + + Download failed with error: %1 + + + + Download finished, but file %1 could not be found. + + + + Download successful. + + + + Save Remote Settings + + + + You have unsaved changes. Do you want to save them? + + + + e.g.: +get DatabaseOnRemote.kdbx {TEMP_DATABASE} +exit +--- +{TEMP_DATABASE} is used as placeholder to store the database in a temporary location +The command has to exit. In case of `sftp` as last command `exit` has to be sent + + + + + e.g.: +put {TEMP_DATABASE} DatabaseOnRemote.kdbx +exit +--- +{TEMP_DATABASE} is used as placeholder to store the database in a temporary location +The command has to exit. In case of `sftp` as last command `exit` has to be sent + + + + + Timeout: + + + + seconds + තත්පර + + DatabaseTabWidget @@ -2322,6 +2574,11 @@ This is definitely a bug, please report it to the developers. Database tab name modifier %1 [Locked] + + %1 [Temporary] + Database tab name modifier + + DatabaseWidget @@ -2445,26 +2702,6 @@ Save changes? File has changed ගොනුව වෙනස් වී ඇත - - The database file has changed. Do you want to load the changes? - දත්ත සමුදා ගොනුව වෙනස් වී ඇත. ඔබට වෙනස්කම් පූරණය කිරීමට අවශ්‍යද? - - - Merge Request - ඒකාබද්ධ ඉල්ලීම - - - The database file has changed and you have unsaved changes. -Do you want to merge your changes? - දත්ත සමුදා ගොනුව වෙනස් වී ඇති අතර ඔබට නොසුරකින ලද වෙනස්කම් ඇත. -ඔබට ඔබගේ වෙනස්කම් ඒකාබද්ධ කිරීමට අවශ්‍යද? - - - Could not open the new database file while attempting to autoreload. -Error: %1 - ස්වයංක්‍රීයව පූරණය කිරීමට උත්සාහ කරන අතරතුර නව දත්ත සමුදා ගොනුව විවෘත කිරීමට නොහැකි විය. -දෝෂය: %1 - Disable safe saves? ආරක්ෂිත සුරැකුම් අබල කරන්නද? @@ -2516,6 +2753,86 @@ Disable safe saves and try again? Database tab name modifier %1 [නව දත්තසමුදාය] + + Remote Sync did not contain any download or upload commands. + + + + Remote sync '%1' completed successfully! + + + + Remote sync '%1' failed: %2 + + + + Error while saving database %1: %2 + + + + Downloading... + + + + Uploading... + + + + Syncing... + + + + Remove passkey from entry + + + + Do you want to remove the passkey from this entry? + + + + The database file "%1" was modified externally + + + + Do you want to load the changes? + + + + Reload database + + + + Reloading database… + + + + Reload canceled + + + + Reload successful + + + + Reload pending user action… + + + + The database file "%1" was modified externally.<br>How would you like to proceed?<br><br>Merge all changes<br>Ignore the changes on disk until save<br>Discard unsaved changes + + + + The database file "%1" was modified externally.<br>How would you like to proceed?<br><br>Merge all changes then save<br>Overwrite the changes on disk<br>Discard unsaved changes + + + + Database file overwritten. + + + + Database file on disk cannot be unlocked with current credentials.<br>Enter new credentials and/or present hardware key to continue. + + EditEntryWidget @@ -2567,10 +2884,6 @@ Disable safe saves and try again? n/a අ/නොවේ - - (encrypted) - (සංකේතිතයි) - Select private key පෞද්. යතුර තෝරන්න @@ -2673,6 +2986,10 @@ Would you like to correct it? %n year(s) වසර %nවසර %n + + Failed to decrypt SSH key, ensure password is correct. + + EditEntryWidgetAdvanced @@ -2844,18 +3161,10 @@ Would you like to correct it? Skip Auto-Submit for this entry මෙම ප්‍රවේශය සඳහා ස්වයංක්‍රීය ඉදිරිපත් කිරීම මඟ හරින්න - - Only send this setting to the browser for HTTP Auth dialogs. If enabled, normal login forms will not show this entry for selection. - HTTP Auth සංවාද සඳහා පමණක් මෙම සැකසුම බ්‍රවුසරයට යවන්න. සබල කර ඇත්නම්, සාමාන්‍ය පිවිසුම් පෝරම තේරීම සඳහා මෙම ප්‍රවේශය නොපෙන්වයි. - Use this entry only with HTTP Basic Auth මෙම ප්‍රවේශය HTTP Basic Auth සමඟ පමණක් භාවිතා කරන්න - - Do not send this setting to the browser for HTTP Auth dialogs. If enabled, HTTP Auth dialogs will not show this entry for selection. - HTTP Auth සංවාද සඳහා මෙම සැකසුම බ්‍රවුසරයට නොයවන්න. සබල කර ඇත්නම්, HTTP Auth සංවාද තේරීම සඳහා මෙම ප්‍රවේශය නොපෙන්වයි. - Do not use this entry with HTTP Basic Auth HTTP Basic Auth සමඟ මෙම ප්‍රවේශය භාවිතා නොකරන්න @@ -2880,6 +3189,14 @@ Would you like to correct it? Additional URLs + + Only send this entry to the browser for HTTP Auth dialogs. If enabled, normal login forms will not show this entry for selection. + + + + Do not send this entry to the browser for HTTP Auth dialogs. If enabled, HTTP Auth dialogs will not show this entry for selection. + + EditEntryWidgetHistory @@ -3102,6 +3419,10 @@ Would you like to correct it? seconds තත්පර + + Clear agent + + EditGroupWidget @@ -3544,6 +3865,24 @@ This may cause the affected plugins to malfunction. %1 - Clone %1 - ක්ලෝනය + + Passkey + + + + Invalid conversion type: %1 + වලංගු නොවන පරිවර්තන වර්ගය: %1 + + + Invalid conversion syntax: %1 + අවලංගු පරිවර්තන වාක්‍ය ඛණ්ඩය: %1 + + + Invalid regular expression syntax %1 +%2 + වලංගු නොවන නිත්‍ය ප්‍රකාශන වාක්‍ය ඛණ්ඩ %1 +%2 + EntryAttachments @@ -3552,6 +3891,21 @@ This may cause the affected plugins to malfunction. "%1"ගොනුව විවෘත කළ නොහැක + + EntryAttachmentsDialog + + Form + පෝරමය + + + File name + + + + File contents... + + + EntryAttachmentsModel @@ -3589,14 +3943,6 @@ This may cause the affected plugins to malfunction. Remove ඉවතලන්න - - Rename selected attachment - තෝරාගත් ඇමුණුම නැවත නම් කරන්න - - - Rename - නැවත නම් කරන්න - Open selected attachment තෝරාගත් ඇමුණුම විවෘත කරන්න @@ -3712,6 +4058,18 @@ Would you like to overwrite the existing attachment? ඇමුණුම "%1" දැනටමත් පවතී. පවතින ඇමුණුම උඩින් ලිවීමට ඔබ කැමතිද? + + New + + + + Preview + පෙරදසුන + + + Failed to preview an attachment: Attachment not found + + EntryAttributesModel @@ -3910,6 +4268,10 @@ Would you like to overwrite the existing attachment? Background Color + + Group Path + + EntryPreviewWidget @@ -4305,6 +4667,14 @@ You can enable the DuckDuckGo website icon service in the security section of th Url + + Could not load key file. + + + + Could not open remote database. Password or key file may be incorrect. + + ImportWizardPageSelect @@ -4408,6 +4778,44 @@ You can enable the DuckDuckGo website icon service in the security section of th KeePass1 Database + + Proton Pass (.json) + + + + Proton Pass JSON Export + + + + Temporary Database + + + + Command: + + + + e.g.: "sftp user@hostname" or "scp user@hostname:DatabaseOnRemote.kdbx {TEMP_DATABASE}" + + + + Input: + + + + e.g.: +get DatabaseOnRemote.kdbx {TEMP_DATABASE} +exit +--- +{TEMP_DATABASE} is used as placeholder to store the database in a temporary location +The command has to exit. In case of `sftp` as last commend `exit` has to be sent + + + + + Remote Database (.kdbx) + + KMessageWidget @@ -5548,12 +5956,6 @@ This version is not meant for production use. Expect some bugs and minor issues, this version is meant for testing purposes. සටහන: ඔබ KeePassXC හි පූර්ව නිකුතුවක් භාවිතා කරයි. සමහර දෝෂ සහ සුළු ගැටළු බලාපොරොත්තු වන්න, මෙම අනුවාදය පරීක්ෂණ අරමුණු සඳහා අදහස් කෙරේ. - - - WARNING: Your Qt version may cause KeePassXC to crash with an On-Screen Keyboard. -We recommend you use the AppImage available on our downloads page. - අවවාදයයි: ඔබේ Qt අනුවාදය KeePassXC තිරයේ යතුරු පුවරුවක් සමඟ බිඳ වැටීමට හේතු විය හැක. -අපගේ බාගැනීම් පිටුවේ ඇති AppImage භාවිතා කිරීමට අපි ඔබට නිර්දේශ කරමු. No Tags @@ -5627,6 +6029,10 @@ We recommend you use the AppImage available on our downloads page. Import Passkey + + Remote S&ync… + + Quit Application @@ -5731,6 +6137,10 @@ We recommend you use the AppImage available on our downloads page. Show Password Generator + + Remove Passkey From Entry + + Perform Auto-Type: {USERNAME} @@ -5875,6 +6285,34 @@ We recommend you use the AppImage available on our downloads page. Toggle Allow Screen Capture + + Show Group Panel + + + + Toggle Show Group Panel + + + + Setup Remote Sync… + + + + Password Generator + + + + E&xpire Entry… + + + + Clear SSH Agent + + + + Clear all identities in ssh-agent + + ManageDatabase @@ -6025,6 +6463,25 @@ We recommend you use the AppImage available on our downloads page. කරුණාකර ඔබගේ නව දත්ත සමුදාය සඳහා සංදර්ශක නාමය සහ විකල්ප විස්තරයක් පුරවන්න: + + NewEntryAttachmentsDialog + + Attachment name cannot be empty + + + + Attachment with the same name already exists + + + + Save attachment + + + + New entry attachment + + + NixUtils @@ -6212,6 +6669,10 @@ We recommend you use the AppImage available on our downloads page. Unexpected EOF when writing private key පුද්ගලික යතුර ලියන විට අනපේක්ෂිත EOF + + (encrypted) + (සංකේතිතයි) + OpenSSHKeyGenDialog @@ -6562,10 +7023,6 @@ The following data is missing: Also choose from: මේවායින් ද තෝරන්න: - - Excluded characters: "0", "1", "l", "I", "O", "|", "﹒" - බැහැර කළ අක්ෂර: "0", "1", "l", "I", "O", "|", "-" - Exclude look-alike characters පෙනුමට සමාන අක්ෂර බැහැර කරන්න @@ -6590,10 +7047,6 @@ The following data is missing: Word Count: වචන ගණන: - - Character Count: - අක්ෂර ගණන: - Word Case: වචන නඩුව: @@ -6606,10 +7059,6 @@ The following data is missing: Add custom wordlist අභිරුචි වචන ලැයිස්තුව එක් කරන්න - - character - ස්වභාවය - Close වසන්න @@ -6716,6 +7165,22 @@ Do you want to overwrite it? Special Characters විශේෂ චරිත + + passwordLength + + + + Characters: %1 + + + + MIXED case + + + + Excluded characters: "0", "1", "l", "I", "O", "|", "﹒", "B", "8", "G", "6" + + PasswordWidget @@ -6783,6 +7248,21 @@ Do you want to overwrite it? අක්ෂර අතර ටැබ් ඔබන්න + + PreviewEntryAttachmentsDialog + + Preview entry attachment + + + + No preview available + + + + Image format not supported + + + QMessageBox @@ -7461,10 +7941,6 @@ Do you want to overwrite it? Invalid word count %1 වලංගු නොවන වචන ගණන %1 - - The word list is too small (< 1000 items) - වචන ලැයිස්තුව කුඩා වැඩියි (අයිතම< 1000) - Title for the entry. ඇතුල්වීම සඳහා මාතෘකාව. @@ -7609,10 +8085,6 @@ Do you want to overwrite it? Exit interactive mode. අන්තර්ක්‍රියාකාරී මාදිලියෙන් පිටවන්න. - - Format to use when exporting. Available choices are 'xml' or 'csv'. Defaults to 'xml'. - අපනයනය කිරීමේදී භාවිතා කළ යුතු ආකෘතිය. පවතින තේරීම් 'xml' හෝ 'csv'වේ. පෙරනිමිය 'xml'. - Exports the content of a database to standard output in the specified format. දත්ත සමුදායක අන්තර්ගතය නියමිත ආකෘතියේ සම්මත ප්‍රතිදානයට අපනයනය කරයි. @@ -8201,18 +8673,6 @@ CPU ගෘහ නිර්මාණ ශිල්පය: %2 file empty ගොනුව හිස් - - malformed string - විකෘති තන්තුව - - - missing closing quote - අවසන් උපුටා දැක්වීම අතුරුදහන් - - - %1: (row, col) %2,%3 - %1: (පේළිය, කොල්) %2,%3 - AES 256-bit AES 256-bit @@ -8657,13 +9117,89 @@ This option is deprecated, use --set-key-file instead. - Unsupported KDF type, cannot decrypt json file + Unknown passkeys error - Unknown passkeys error + Invalid KDF iterations, cannot decrypt json file + + Unsupported format, ensure your Bitwarden export is password-protected + + + + Only PBKDF and Argon2 are supported, cannot decrypt json file + + + + Reset Shortcuts + + + + Double click an action to change its shortcut + + + + Filter... + + + + Shortcut Conflict + + + + Shortcut %1 conflicts with '%2'. Overwrite shortcut? + + + + Cannot generate valid passphrases because the wordlist is too short + + + + Encrypted files are not supported. + + + + Proton Pass Import + + + + Delete plugin data? + ප්ලගින දත්ත මකන්නද? + + + Delete plugin data from Entry(s)? + + + + Passkey + + + + Format to use when exporting. Available choices are 'xml', 'csv' or 'html'. Defaults to 'xml'. + + + + start minimized to the system tray + + + + malformed string, possible unescaped delimiter + + + + missing closing delimiter + + + + %1, row: %2, column: %3 + + + + Tags + අනන්‍යන + QtIOCompressor @@ -8699,6 +9235,37 @@ This option is deprecated, use --set-key-file instead. අභ්‍යන්තර zlib දෝෂය: + + RemoteHandler + + Command `%1` did not finish in time. Process was killed. + + + + Failed to upload merged database. Command `%1` did not finish in time. Process was killed. + + + + Invalid download parameters provided. + + + + Command `%1` failed to download database. + + + + Invalid database pointer or upload parameters provided. + + + + Command `%1` exited with status code: %2 + + + + Failed to upload merged database. Command `%1` exited with status code: %2 + + + ReportsWidgetBrowserStatistics @@ -8765,6 +9332,10 @@ This option is deprecated, use --set-key-file instead. Exclude from reports වාර්තා වලින් බැහැර කරන්න + + Expire Entry(s)… + + Only show entries that have a URL @@ -8781,36 +9352,33 @@ This option is deprecated, use --set-key-file instead. (Expired) + + Delete plugin data from Entry(s)… + + ReportsWidgetHealthcheck - Hover over reason to show additional details. Double-click entries to edit. - අමතර විස්තර පෙන්වීමට හේතුව මත සැරිසරන්න. සංස්කරණය කිරීමට ඇතුළත් කිරීම් ද්විත්ව ක්ලික් කරන්න. + Show expired entries + - Bad - Password quality - නරක + (Expired) + + + + Hover over reason to show additional details. Double-click entries to edit. + අමතර විස්තර පෙන්වීමට හේතුව මත සැරිසරන්න. සංස්කරණය කිරීමට ඇතුළත් කිරීම් ද්විත්ව ක්ලික් කරන්න. Bad — password must be changed නරකයි - මුරපදය වෙනස් කළ යුතුය - - Poor - Password quality - දුප්පත් - Poor — password should be changed දුර්වල - මුරපදය වෙනස් කළ යුතුය - - Weak - Password quality - දුර්වල - Weak — consider changing the password දුර්වලයි - මුරපදය වෙනස් කිරීම සලකා බලන්න @@ -8859,18 +9427,14 @@ This option is deprecated, use --set-key-file instead. Exclude from reports වාර්තා වලින් බැහැර කරන්න - - Show expired entries - + + Expire Entry(s)… + Show entries that have been excluded from reports - - (Expired) - - ReportsWidgetHibp @@ -8966,6 +9530,10 @@ This option is deprecated, use --set-key-file instead. Exclude from reports වාර්තා වලින් බැහැර කරන්න + + Expire Entry(s)… + + ReportsWidgetPasskeys @@ -9207,6 +9775,14 @@ This option is deprecated, use --set-key-file instead. No agent running, cannot list identities. කිසිදු නියෝජිතයෙකු ක්‍රියාත්මක නොවේ, අනන්‍යතා ලැයිස්තුගත කළ නොහැක. + + Failed to remove all SSH identities from agent. + + + + All SSH identities removed from agent. + + SearchHelpWidget @@ -9492,29 +10068,6 @@ This option is deprecated, use --set-key-file instead. %1වෙත අපනයනය කරන්න - - ShortcutSettingsWidget - - Double click an action to change its shortcut - - - - Shortcut Conflict - - - - Filter... - - - - Shortcut %1 conflicts with '%2'. Overwrite shortcut? - - - - Reset Shortcuts - - - TagModel @@ -9804,11 +10357,15 @@ Example: JBSWY3DPEHPK3PXP දෘඩාංග යතුරු අනාවරණය කර නොමැත - <p>If you own a <a href="https://www.yubico.com/">YubiKey</a> or <a href="https://onlykey.io">OnlyKey</a>, you can use it for additional security.</p><p>The key requires one of its slots to be programmed as <a href="https://docs.yubico.com/yesdk/users-manual/application-otp/challenge-response.html">HMAC-SHA1 Challenge-Response</a>.</p> + Refresh hardware keys - Refresh hardware keys + <p>If you own a <a href="https://www.yubico.com/">YubiKey</a> or <a href="https://onlykey.io">OnlyKey</a>, you can use it for additional security.</p><p>The key requires one of its slots to be programmed with <a href="https://keepassxc.org/docs/#faq-yubikey-howto">Challenge-Response</a>.</p> + + + + Hardware keys found, but no slots are configured diff --git a/share/translations/keepassxc_sk.ts b/share/translations/keepassxc_sk.ts index 13b461dd2..3539d4d4b 100644 --- a/share/translations/keepassxc_sk.ts +++ b/share/translations/keepassxc_sk.ts @@ -217,18 +217,50 @@ You must restart the application to set the new language. Would you like to restart now? Musíte reštartovať aplikáciu, aby sa tieto zmeny prejavili. Chcete ju reštartovať teraz? - - Reset Settings? - Resetovať nastavenia? - - - Are you sure you want to reset all general and security settings to default? - Naozaj chcete obnoviť všetky všeobecné nastavenia na predvolené hodnoty? - Select backup storage directory Vyberte priečinok pre uloženie zálohy + + Confirm Reset + + + + Are you sure you want to reset all settings to default? + + + + Import KeePassXC Settings + + + + Failed to import settings from %1, not a valid settings file. + + + + Export KeePassXC Settings + + + + Small + + + + Normal + + + + Medium + + + + Large + + + + Custom + + ApplicationSettingsWidgetGeneral @@ -280,25 +312,6 @@ Include beta releases when checking for updates Pri kontrole aktualizácii zahrnúť pred-vydania - - On database unlock, show entries that - - - - have expired - On database unlock, show entries that... - - - - days - On database unlock, show entries that will expire within %1 days - - - - will expire within - On database unlock, show entries that... - - File Management Správa súborov @@ -323,22 +336,10 @@ Backup database file before saving Zálohovať databázu pri každom uložení - - Backup destination - - - - Specifies the database backup file location. Occurrences of "{DB_FILENAME}" are replaced with the filename of the saved database without extension. {TIME:<format>} is replaced with the backup time, see https://doc.qt.io/qt-5/qdatetime.html#toString. <format> defaults to format string "dd_MM_yyyy_hh-mm-ss". - - {DB_FILENAME}.old.kdbx - - Choose... - - Use alternative saving method (may solve problems with Dropbox, Google Drive, GVFS, etc.) @@ -505,6 +506,71 @@ Remember last typed entry for: + + On database unlock, show entries that will expire within + + + + On database unlock, show entries that will expire within + + + + days + number of days warning for password expiration + + + + Destination format: + + + + <html><head/><body><p><span style=" font-weight:600;">{DB_FILENAME}</span> is replaced with the filename of the saved database without extension</p><p><span style=" font-weight:600;">{TIME:&lt;format&gt;}</span> is replaced with the specified time format (default: dd_MM_yyyy_hh-mm-ss)</p><p>See the User Guide for more details</p></body></html> + + + + Choose folder... + + + + Show confirmation before moving entries to recycle bin + + + + Copy data on double clicking field in entry view + + + + Show toolbar + + + + Show the menu bar by pressing the Alt key + + + + Show menubar + + + + Import settings… + + + + Export settings… + + + + Open browser on double clicking URL field in entry view + + + + Font size: + + + + Font size selection + + ApplicationSettingsWidgetSecurity @@ -570,18 +636,6 @@ Hide passwords in the entry preview panel Skryť heslá v paneli ukážky položky - - Hide entry notes by default - Predvolene skryť poznámky položky - - - Move entries to recycle bin without confirmation - Položky presunúť do koša bez potvrdenia - - - Enable double click to copy the username/password entry columns - Povoliť kopírovanie stĺpcov používateľské meno/heslo dvojklikom - Privacy Súkromie @@ -594,6 +648,18 @@ Hide TOTP in the entry preview panel + + Lock databases when switching user + + + + Lock Options + + + + Hide notes in the entry preview panel + + AutoType @@ -641,20 +707,6 @@ Entry does not have attribute for PICKCHARS: %1 - - Invalid conversion type: %1 - Neplatný typ konverzie: %1 - - - Invalid conversion syntax: %1 - Neplatná syntax konverzie: %1 - - - Invalid regular expression syntax %1 -%2 - Neplatná syntax regulárneho výrazu %1 -%2 - Invalid placeholder: %1 @@ -1017,10 +1069,6 @@ Do you want to overwrite the passkey in %1 - %2? General Všeobecné - - Browsers installed as snaps are currently not supported. - Boli nainštalované prehliadače lebo "snaps" momentálne nie sú podporované. - Enable integration for these browsers: Zapnúť integráciu v týchto prehliadačoch: @@ -1192,18 +1240,6 @@ Do you want to overwrite the passkey in %1 - %2? Custom extension ID Vlastné ID rozšírenia - - Due to Snap sandboxing, you must run a script to enable browser integration.<br />You can obtain this script from %1 - Kvôli ochrane Snap v sandboxe, musíte na povolenie integrácie prehliadača spustiť skript.<br />Skript môžete získať z %1 - - - KeePassXC-Browser is needed for the browser integration to work. <br />Download it for %1 and %2 and %3. %4 - Na fungovanie integrácie s prehliadačom je potrebný KeePassXC-Browser.<br /> Stiahnite ho pre %1 a %2. %3. %4 - - - Please see special instructions for browser extension use below - Prosím, pozrite si špeciálne inštrukcie na použite integrácie prehliadača nižšie - Executable Files Spustiteľné súbory @@ -1252,6 +1288,14 @@ Do you want to overwrite the passkey in %1 - %2? Allow using localhost with passkeys + + KeePassXC-Browser is needed for the browser integration to work. <br />Download it for %1 and %2 and %3. + + + + Browsers installed using Snap or Flatpak are not supported with exception to Firefox installed using Snap. + + CloneDialog @@ -1394,6 +1438,19 @@ Do you want to overwrite the passkey in %1 - %2? Imported from CSV file: %1 + + No Title Selected + + + + No title column was selected, entries will be hard to tell apart. +Are you sure you want to import? + + + + Tags + + CsvParserModel @@ -1457,6 +1514,14 @@ Zálohovať databázu nachádzajúcu sa na %2 Recycle Bin Kôš + + Database file read error. + + + + No file path was provided. + + DatabaseOpenDialog @@ -1599,14 +1664,6 @@ Ak chcete zabrániť zobrazovaniu tejto chyby, musíte ísť do "Nastavenia <p>In addition to a password, you can use a secret file to enhance the security of your database. This file can be generated in your database's security settings.</p><p>This is <strong>not</strong> your *.kdbx database file!</p> - - Click to add a key file. - - - - <a href="#" style="text-decoration: underline">I have a key file</a> - - Use hardware key [Serial: %1] @@ -1639,6 +1696,18 @@ Are you sure you want to continue with this file?. Refresh Hardware Keys + + Click to add a key file. + + + + <a href="#" style="text-decoration: underline">I have a key file</a> + + + + Hardware keys found, but no slots are configured. + + DatabaseSettingWidgetMetaData @@ -1673,6 +1742,22 @@ Are you sure you want to continue with this file?. Maintenance Údržba + + KeeShare + KeeShare + + + Secret Service Integration + Integrácia Tajnej služby + + + Remote Sync + + + + Database Settings: %1 + + DatabaseSettingsWidgetBrowser @@ -1844,11 +1929,11 @@ Naozaj chcete pokračovať bez hesla? Slabé heslo - You must enter a stronger password to protect your database. + This is a weak password! For better protection of your secrets, you should choose a stronger password. - This is a weak password! For better protection of your secrets, you should choose a stronger password. + The provided password does not meet the minimum quality requirement. @@ -2143,6 +2228,50 @@ removed from the database. Autosave delay since last change checkbox + + Public Database Metadata + + + + Warning: the following settings are not encrypted. + + + + Display name: + + + + Publically visible display name used on the unlock dialog + + + + Database public display name + + + + Display color: + + + + Publically visible color used on the unlock dialog + + + + Database public display color chooser + + + + Clear + Vymazať + + + Display icon: + + + + Select Database Icon + + DatabaseSettingsWidgetKeeShare @@ -2238,6 +2367,129 @@ removed from the database. Pole popisu databázy + + DatabaseSettingsWidgetRemote + + Sync Commands + + + + Remove + Odstrániť + + + Command Settings + + + + Name + Názov + + + Save + Uložiť + + + Download + + + + Command: + + + + Download command field + + + + e.g.: "sftp user@hostname" or "scp user@hostname:DatabaseOnRemote.kdbx {TEMP_DATABASE}" + + + + Input: + + + + Download input field + + + + Upload + + + + Upload command field + + + + e.g.: "sftp user@hostname" or "scp {TEMP_DATABASE} user@hostname:DatabaseOnRemote.kdbx" + + + + Upload input field + + + + Name cannot be empty. + + + + Test + + + + Download command cannot be empty. + + + + Download failed with error: %1 + + + + Download finished, but file %1 could not be found. + + + + Download successful. + + + + Save Remote Settings + + + + You have unsaved changes. Do you want to save them? + + + + e.g.: +get DatabaseOnRemote.kdbx {TEMP_DATABASE} +exit +--- +{TEMP_DATABASE} is used as placeholder to store the database in a temporary location +The command has to exit. In case of `sftp` as last command `exit` has to be sent + + + + + e.g.: +put {TEMP_DATABASE} DatabaseOnRemote.kdbx +exit +--- +{TEMP_DATABASE} is used as placeholder to store the database in a temporary location +The command has to exit. In case of `sftp` as last command `exit` has to be sent + + + + + Timeout: + + + + seconds + sekundy + + DatabaseTabWidget @@ -2311,6 +2563,11 @@ Toto je určite chyba, prosím nahláste ju vývojárom. Database tab name modifier %1 [Zamknutá] + + %1 [Temporary] + Database tab name modifier + + DatabaseWidget @@ -2434,26 +2691,6 @@ Uložiť zmeny? File has changed Súbor bol zmenený - - The database file has changed. Do you want to load the changes? - Súbor databázy bol zmenený. Chcete načítať zmeny? - - - Merge Request - Požiadavka zlúčenia - - - The database file has changed and you have unsaved changes. -Do you want to merge your changes? - Súbor databázy bol zmenený a Vy máte neuložené zmeny. -Chcete zlúčiť svoje zmeny? - - - Could not open the new database file while attempting to autoreload. -Error: %1 - Nemožno otvoriť nový databázový súbor počas pokusu o automatické opätovné načítanie. -Chyba: %1 - Disable safe saves? Vypnúť bezpečné ukladanie? @@ -2505,6 +2742,86 @@ Vypnúť bezpečné ukladanie a skúsiť znova? Database tab name modifier %1 [Nová databáza] + + Remote Sync did not contain any download or upload commands. + + + + Remote sync '%1' completed successfully! + + + + Remote sync '%1' failed: %2 + + + + Error while saving database %1: %2 + + + + Downloading... + Sťahovanie… + + + Uploading... + + + + Syncing... + + + + Remove passkey from entry + + + + Do you want to remove the passkey from this entry? + + + + The database file "%1" was modified externally + + + + Do you want to load the changes? + + + + Reload database + + + + Reloading database… + + + + Reload canceled + + + + Reload successful + + + + Reload pending user action… + + + + The database file "%1" was modified externally.<br>How would you like to proceed?<br><br>Merge all changes<br>Ignore the changes on disk until save<br>Discard unsaved changes + + + + The database file "%1" was modified externally.<br>How would you like to proceed?<br><br>Merge all changes then save<br>Overwrite the changes on disk<br>Discard unsaved changes + + + + Database file overwritten. + + + + Database file on disk cannot be unlocked with current credentials.<br>Enter new credentials and/or present hardware key to continue. + + EditEntryWidget @@ -2556,10 +2873,6 @@ Vypnúť bezpečné ukladanie a skúsiť znova? n/a neznáme - - (encrypted) - (šifrované) - Select private key Zvoľte súkromný kľúč @@ -2661,6 +2974,10 @@ Chcete to opraviť? %n year(s) %n rok%n roky%n rokov%n rokov + + Failed to decrypt SSH key, ensure password is correct. + + EditEntryWidgetAdvanced @@ -2832,18 +3149,10 @@ Chcete to opraviť? Skip Auto-Submit for this entry Zapnúť Automatické vypĺňanie pre túto položku - - Only send this setting to the browser for HTTP Auth dialogs. If enabled, normal login forms will not show this entry for selection. - Toto nastavenie posielať do prehliadača len pre dialógy HTTP Auth. Ak je zapnuté, bežné prihlasovacie formuláre nebudú na výber poskytovať túto položku. - Use this entry only with HTTP Basic Auth Použiť položku len pre HTTP Basic Auth - - Do not send this setting to the browser for HTTP Auth dialogs. If enabled, HTTP Auth dialogs will not show this entry for selection. - Toto nastavenie neposielať do prehliadača pre dialógy HTTP Auth. Ak je zapnuté, bežné prihlasovacie formuláre nebudú na výber poskytovať túto položku. - Do not use this entry with HTTP Basic Auth Nepoužiť túto položku pre HTTP Basic Auth @@ -2868,6 +3177,14 @@ Chcete to opraviť? Additional URLs + + Only send this entry to the browser for HTTP Auth dialogs. If enabled, normal login forms will not show this entry for selection. + + + + Do not send this entry to the browser for HTTP Auth dialogs. If enabled, HTTP Auth dialogs will not show this entry for selection. + + EditEntryWidgetHistory @@ -3090,6 +3407,10 @@ Chcete to opraviť? seconds sekundy + + Clear agent + + EditGroupWidget @@ -3532,6 +3853,24 @@ Môže to spôsobiť nefunkčnosť dotknutých zásuvných modulov.%1 - Clone %1 – Klon + + Passkey + + + + Invalid conversion type: %1 + Neplatný typ konverzie: %1 + + + Invalid conversion syntax: %1 + Neplatná syntax konverzie: %1 + + + Invalid regular expression syntax %1 +%2 + Neplatná syntax regulárneho výrazu %1 +%2 + EntryAttachments @@ -3540,6 +3879,21 @@ Môže to spôsobiť nefunkčnosť dotknutých zásuvných modulov.Nemožno otvoriť súbor „%1”. + + EntryAttachmentsDialog + + Form + Formulár + + + File name + + + + File contents... + + + EntryAttachmentsModel @@ -3577,14 +3931,6 @@ Môže to spôsobiť nefunkčnosť dotknutých zásuvných modulov.Remove Odstrániť - - Rename selected attachment - Premenovať zvolenú prílohu - - - Rename - Premenovať - Open selected attachment Otvoriť zvolenú prílohu @@ -3702,6 +4048,18 @@ Would you like to overwrite the existing attachment? Príloha "%1" už existuje. Prepísať existujúcu prílohu? + + New + + + + Preview + Ukážka + + + Failed to preview an attachment: Attachment not found + + EntryAttributesModel @@ -3900,6 +4258,10 @@ Prepísať existujúcu prílohu? Background Color + + Group Path + + EntryPreviewWidget @@ -4295,6 +4657,14 @@ V bezpečnostnej sekcii nastavení aplikácie môžete zapnúť webovú službu Url + + Could not load key file. + + + + Could not open remote database. Password or key file may be incorrect. + + ImportWizardPageSelect @@ -4398,6 +4768,44 @@ V bezpečnostnej sekcii nastavení aplikácie môžete zapnúť webovú službu KeePass1 Database + + Proton Pass (.json) + + + + Proton Pass JSON Export + + + + Temporary Database + + + + Command: + + + + e.g.: "sftp user@hostname" or "scp user@hostname:DatabaseOnRemote.kdbx {TEMP_DATABASE}" + + + + Input: + + + + e.g.: +get DatabaseOnRemote.kdbx {TEMP_DATABASE} +exit +--- +{TEMP_DATABASE} is used as placeholder to store the database in a temporary location +The command has to exit. In case of `sftp` as last commend `exit` has to be sent + + + + + Remote Database (.kdbx) + + KMessageWidget @@ -5539,12 +5947,6 @@ Táto verzia nie je určená na produkčné použitie. Expect some bugs and minor issues, this version is meant for testing purposes. UPOZORNENIE: Používate predbežnú verziu KeePassXC. Očakávajte chyby a menšie problémy, tato verzia je určená pre testovacie účely. - - - WARNING: Your Qt version may cause KeePassXC to crash with an On-Screen Keyboard. -We recommend you use the AppImage available on our downloads page. - UPOZORNENIE: Vaša verzia Qt môže spôsobiť pád KeePassXC s klávesnicou na obrazovke! -Odporúčame použiť AppImage dostupný na našej stránke sťahovaní. No Tags @@ -5618,6 +6020,10 @@ Odporúčame použiť AppImage dostupný na našej stránke sťahovaní.Import Passkey + + Remote S&ync… + + Quit Application @@ -5722,6 +6128,10 @@ Odporúčame použiť AppImage dostupný na našej stránke sťahovaní.Show Password Generator + + Remove Passkey From Entry + + Perform Auto-Type: {USERNAME} @@ -5866,6 +6276,34 @@ Odporúčame použiť AppImage dostupný na našej stránke sťahovaní.Toggle Allow Screen Capture + + Show Group Panel + + + + Toggle Show Group Panel + + + + Setup Remote Sync… + + + + Password Generator + Generátor hesla + + + E&xpire Entry… + + + + Clear SSH Agent + + + + Clear all identities in ssh-agent + + ManageDatabase @@ -6016,6 +6454,25 @@ Odporúčame použiť AppImage dostupný na našej stránke sťahovaní.Prosím, vyplňte meno a prípadne aj popis svojej novej databázy: + + NewEntryAttachmentsDialog + + Attachment name cannot be empty + + + + Attachment with the same name already exists + + + + Save attachment + + + + New entry attachment + + + NixUtils @@ -6203,6 +6660,10 @@ Odporúčame použiť AppImage dostupný na našej stránke sťahovaní.Unexpected EOF when writing private key Neočakávaný koniec súboru pri zápise súkromného kľúča + + (encrypted) + (šifrované) + OpenSSHKeyGenDialog @@ -6553,10 +7014,6 @@ The following data is missing: Also choose from: Tiež vybrať z: - - Excluded characters: "0", "1", "l", "I", "O", "|", "﹒" - Vynechané znaky: „0”, „1”, „l”, „I”, „O”, „|”, „﹒” - Exclude look-alike characters Vynechať podobne vyzerajúce znaky @@ -6581,10 +7038,6 @@ The following data is missing: Word Count: Počet slov: - - Character Count: - Počet znakov: - Word Case: Slová veľkými: @@ -6597,10 +7050,6 @@ The following data is missing: Add custom wordlist Pridať vlastný zoznam slov - - character - znak - Close Zatvoriť @@ -6706,6 +7155,22 @@ Do you want to overwrite it? Special Characters Špeciálne znaky + + passwordLength + + + + Characters: %1 + + + + MIXED case + + + + Excluded characters: "0", "1", "l", "I", "O", "|", "﹒", "B", "8", "G", "6" + + PasswordWidget @@ -6773,6 +7238,21 @@ Do you want to overwrite it? + + PreviewEntryAttachmentsDialog + + Preview entry attachment + + + + No preview available + + + + Image format not supported + + + QMessageBox @@ -7451,10 +7931,6 @@ Do you want to overwrite it? Invalid word count %1 Neplatný počet slov %1 - - The word list is too small (< 1000 items) - Zoznam slov je príliš krátky (< 1000 položiek) - Title for the entry. Názov položky. @@ -7599,10 +8075,6 @@ Do you want to overwrite it? Exit interactive mode. Ukončiť interaktívny režim. - - Format to use when exporting. Available choices are 'xml' or 'csv'. Defaults to 'xml'. - Formát exportu. Dostupné voľby sú „xml” alebo „csv”. Predvolene „xml”. - Exports the content of a database to standard output in the specified format. Exportuje obsah databázy na štandardný výstup v zadanom formáte. @@ -8190,18 +8662,6 @@ Jadro: %3 %4 file empty prázdny súbor - - malformed string - zlý formát reťazca - - - missing closing quote - chýba koncová úvodzovka - - - %1: (row, col) %2,%3 - %1: (riadok, stĺpec) %2, %3 - AES 256-bit AES 256b @@ -8646,11 +9106,87 @@ This option is deprecated, use --set-key-file instead. - Unsupported KDF type, cannot decrypt json file + Unknown passkeys error - Unknown passkeys error + Invalid KDF iterations, cannot decrypt json file + + + + Unsupported format, ensure your Bitwarden export is password-protected + + + + Only PBKDF and Argon2 are supported, cannot decrypt json file + + + + Reset Shortcuts + + + + Double click an action to change its shortcut + + + + Filter... + + + + Shortcut Conflict + + + + Shortcut %1 conflicts with '%2'. Overwrite shortcut? + + + + Cannot generate valid passphrases because the wordlist is too short + + + + Encrypted files are not supported. + + + + Proton Pass Import + + + + Delete plugin data? + Odstrániť dáta zásuvného modulu? + + + Delete plugin data from Entry(s)? + + + + Passkey + + + + Format to use when exporting. Available choices are 'xml', 'csv' or 'html'. Defaults to 'xml'. + + + + start minimized to the system tray + + + + malformed string, possible unescaped delimiter + + + + missing closing delimiter + + + + %1, row: %2, column: %3 + + + + Tags @@ -8688,6 +9224,37 @@ This option is deprecated, use --set-key-file instead. Interná chyba zlib: + + RemoteHandler + + Command `%1` did not finish in time. Process was killed. + + + + Failed to upload merged database. Command `%1` did not finish in time. Process was killed. + + + + Invalid download parameters provided. + + + + Command `%1` failed to download database. + + + + Invalid database pointer or upload parameters provided. + + + + Command `%1` exited with status code: %2 + + + + Failed to upload merged database. Command `%1` exited with status code: %2 + + + ReportsWidgetBrowserStatistics @@ -8754,6 +9321,10 @@ This option is deprecated, use --set-key-file instead. Exclude from reports Vylúčiť z hlásení + + Expire Entry(s)… + + Only show entries that have a URL @@ -8770,36 +9341,33 @@ This option is deprecated, use --set-key-file instead. (Expired) + + Delete plugin data from Entry(s)… + + ReportsWidgetHealthcheck - Hover over reason to show additional details. Double-click entries to edit. - Prejdite myšou na príčinou, na zobrazenie dodatočných podrobností. Dvojklikom na položku ju upravíte. + Show expired entries + - Bad - Password quality - Zlé + (Expired) + + + + Hover over reason to show additional details. Double-click entries to edit. + Prejdite myšou na príčinou, na zobrazenie dodatočných podrobností. Dvojklikom na položku ju upravíte. Bad — password must be changed Zlé — heslo treba zmeniť - - Poor - Password quality - Biedne - Poor — password should be changed Biedne — heslo by ste mali zmeniť - - Weak - Password quality - Slabé - Weak — consider changing the password Slabé — zvážte zmenu hesla @@ -8848,18 +9416,14 @@ This option is deprecated, use --set-key-file instead. Exclude from reports Vylúčiť z hlásení - - Show expired entries - + + Expire Entry(s)… + Show entries that have been excluded from reports - - (Expired) - - ReportsWidgetHibp @@ -8955,6 +9519,10 @@ This option is deprecated, use --set-key-file instead. Exclude from reports Vylúčiť z hlásení + + Expire Entry(s)… + + ReportsWidgetPasskeys @@ -9196,6 +9764,14 @@ This option is deprecated, use --set-key-file instead. No agent running, cannot list identities. Nie je spustený agent, nemožno získať zoznam identít. + + Failed to remove all SSH identities from agent. + + + + All SSH identities removed from agent. + + SearchHelpWidget @@ -9481,29 +10057,6 @@ This option is deprecated, use --set-key-file instead. Exportovať do %1 - - ShortcutSettingsWidget - - Double click an action to change its shortcut - - - - Shortcut Conflict - - - - Filter... - - - - Shortcut %1 conflicts with '%2'. Overwrite shortcut? - - - - Reset Shortcuts - - - TagModel @@ -9793,11 +10346,15 @@ Napríklad: JBSWY3DPEHPK3PXP Nenájdené žiadne hardvérové kľúče - <p>If you own a <a href="https://www.yubico.com/">YubiKey</a> or <a href="https://onlykey.io">OnlyKey</a>, you can use it for additional security.</p><p>The key requires one of its slots to be programmed as <a href="https://docs.yubico.com/yesdk/users-manual/application-otp/challenge-response.html">HMAC-SHA1 Challenge-Response</a>.</p> + Refresh hardware keys - Refresh hardware keys + <p>If you own a <a href="https://www.yubico.com/">YubiKey</a> or <a href="https://onlykey.io">OnlyKey</a>, you can use it for additional security.</p><p>The key requires one of its slots to be programmed with <a href="https://keepassxc.org/docs/#faq-yubikey-howto">Challenge-Response</a>.</p> + + + + Hardware keys found, but no slots are configured diff --git a/share/translations/keepassxc_sl.ts b/share/translations/keepassxc_sl.ts index 2bb3342b1..1c95d7ed2 100644 --- a/share/translations/keepassxc_sl.ts +++ b/share/translations/keepassxc_sl.ts @@ -150,10 +150,6 @@ SSH Agent connection is working! Povezava s SSH agentom deluje! - - Use both agents - - ApplicationSettingsWidget @@ -225,10 +221,6 @@ Select backup storage directory - - This setting cannot be enabled when minimize on unlock is enabled. - - ApplicationSettingsWidgetGeneral @@ -497,14 +489,6 @@ Remember last typed entry for: - - recent files - - - - Show passwords in color - - ApplicationSettingsWidgetSecurity @@ -654,10 +638,6 @@ Invalid placeholder: %1 - - Entry does not have attribute for PICKCHARS: %1 - - AutoTypeAssociationsModel @@ -1427,6 +1407,10 @@ Varnostna kopija baze se nahaja na %2 Key File: Datoteka s ključi: + + <p>In addition to a password, you can use a secret file to enhance the security of your database. This file can be generated in your database's security settings.</p><p>This is <strong>not</strong> your *.kdbx database file!<br>If you do not have a key file, leave this field empty.</p><p>Click for more information…</p> + + Key file help @@ -1439,6 +1423,11 @@ Varnostna kopija baze se nahaja na %2 Hardware Key: + + <p>You can use a hardware security key such as a <strong>YubiKey</strong> or <strong>OnlyKey</strong> with slots configured for HMAC-SHA1.</p> +<p>Click for more information…</p> + + Hardware key help @@ -1573,15 +1562,6 @@ If you do not have a key file, please leave the field empty. Select hardware key… - - <p>In addition to a password, you can use a secret file to enhance the security of your database. This file can be generated in your database's security settings.</p><p>This is <strong>not</strong> your *.kdbx database file!<br>If you do not have a key file, leave this field empty.</p><p>Click for more information…</p> - - - - <p>You can use a hardware security key such as a <strong>YubiKey</strong> or <strong>OnlyKey</strong> with slots configured for HMAC-SHA1.</p> -<p>Click for more information…</p> - - DatabaseSettingWidgetMetaData @@ -2222,21 +2202,13 @@ This is definitely a bug, please report it to the developers. Database tab name modifier %1 [Zaklenjeno] - - Export database to XML file - - - - XML file - - - - Writing the XML file failed - - DatabaseWidget + + Database Tags + + Searching… @@ -2401,22 +2373,6 @@ Disable safe saves and try again? Entries expiring within %1 day(s) - - Searches and Tags - - - - Enter a unique name or overwrite an existing search from the list: - - - - Save - Shrani - - - Save Search - - EditEntryWidget @@ -2554,6 +2510,10 @@ Would you like to correct it? Hide Skrij + + Tomorrow + Jutri + %n week(s) %n ted(ov)%n ted(ov)%n ted(ov)%n teden(ov) @@ -2566,10 +2526,6 @@ Would you like to correct it? %n year(s) %n let%n let%n let%n let - - %n hour(s) - - EditEntryWidgetAdvanced @@ -3085,14 +3041,6 @@ Would you like to correct it? Do not use HTTP Auth toggle for this and sub groups - - Omit WWW subdomain from matching: - - - - Omit WWW subdomain from matching toggle for this and sub groups - - EditGroupWidgetKeeShare @@ -3675,10 +3623,6 @@ Error: %1 Auto-Type Samodejno tipkanje - - Tags - - EntryModel @@ -3886,10 +3830,6 @@ Error: %1 Disabled Onemogočen - - Double click to copy value - - EntryURLModel @@ -5379,30 +5319,6 @@ We recommend you use the AppImage available on our downloads page. You must restart the application to apply this setting. Would you like to restart now? Če želite uporabiti to nastavitev, morate znova zagnati aplikacijo. Ali želite znova zagnati zdaj? - - Tags - - - - No Tags - - - - %1 Entry(s) - - - - Copy Password and TOTP - - - - &XML File… - - - - XML File… - - ManageDatabase @@ -5773,6 +5689,29 @@ We recommend you use the AppImage available on our downloads page. + + PasswordEdit + + Passwords do not match + + + + Passwords match so far + + + + Toggle Password (%1) + + + + Generate Password (%1) + + + + Warning: Caps Lock enabled! + + + PasswordEditWidget @@ -5951,6 +5890,10 @@ We recommend you use the AppImage available on our downloads page. Also choose from: Izberi tudi med: + + Excluded characters: "0", "1", "l", "I", "O", "|", "﹒" + + Exclude look-alike characters Izključi podobne znake @@ -6100,57 +6043,6 @@ Do you want to overwrite it? Password quality Odlična - - Excluded characters: "0", "1", "l", "I", "O", "|", "﹒" - - - - - PasswordWidget - - Passwords do not match - - - - Passwords match so far - - - - Toggle Password (%1) - - - - Generate Password (%1) - - - - Warning: Caps Lock enabled! - - - - Quality: %1 - - - - Poor - Password quality - Slabo - - - Weak - Password quality - Šibko - - - Good - Password quality - Dobra - - - Excellent - Password quality - Odlična - PickcharsDialog @@ -7279,6 +7171,10 @@ Please consider generating a new key file. Invalid YubiKey serial %1 + + Please present or touch your YubiKey to continue… + + Enter password to encrypt database (optional): Vnesite geslo za šifriranje baze (neobvezno): @@ -7756,67 +7652,6 @@ Jedro: %3 %4 Failed to sign challenge using Windows Hello. - - Please present or touch your YubiKey to continue. - - - - Show all the attributes of the entry. - - - - Edit a database. - - - - Could not change the database key. - - - - Database was not modified. - - - - Successfully edited the database. - - - - Loading the new key file failed: %1 - - - - Unset the password for the database. - - - - Unset the key file for the database. - - - - Cannot use %1 and %2 at the same time. - - - - Cannot remove all the keys from a database. - - - - Cannot remove password: The database does not have a password. - - - - Cannot remove file key: The database does not have a file key. - - - - Found unexpected Key type %1 - - - - Set the key file for the database. -This options is deprecated, use --set-key-file instead. - - QtIOCompressor @@ -8364,10 +8199,6 @@ This options is deprecated, use --set-key-file instead. Limit search to selected group - - Save Search - - SettingsClientModel @@ -8580,6 +8411,10 @@ This options is deprecated, use --set-key-file instead. TagModel + + All + + Expired @@ -8588,33 +8423,6 @@ This options is deprecated, use --set-key-file instead. Weak Passwords - - All Entries - - - - Clear Search - - - - - TagView - - Remove Search - - - - Remove Tag - - - - Confirm Remove Tag - - - - Remove tag "%1" from all entries in this database? - - TotpDialog diff --git a/share/translations/keepassxc_sq.ts b/share/translations/keepassxc_sq.ts index ebcf8eca3..41f7e88b9 100644 --- a/share/translations/keepassxc_sq.ts +++ b/share/translations/keepassxc_sq.ts @@ -80,6 +80,10 @@ Details Hollësi + + Your decision will be remembered for the duration while both the requesting client AND KeePassXC are running. + Vendimi juaj do të mbahet mend për kohëzgjatjen, teksa xhirojnë që të dy, klienti DHE KeePassXC-ja. + Remember Mbaje mend @@ -88,10 +92,6 @@ Allow Selected Lejo të Përzgjedhurin - - Your decision will be remembered for the duration while both the requesting client AND KeePassXC are running. - Vendimi juaj do të mbhet mend për kohëzgjatjen, teksa xhirojnë që të dy, klienti DHE KeePassXC-ja. - Deny All && Future Moho Krejt të && Ardhmet @@ -122,6 +122,10 @@ Use OpenSSH Përdor OpenSSH + + Use both agents + Përdoru të dy agjentët + SSH_AUTH_SOCK override Anashkalim SSH_AUTH_SOCK @@ -144,16 +148,12 @@ No SSH Agent socket available. Either make sure SSH_AUTH_SOCK environment variable exists or set an override. - + S’ka kanal Agjenti SSH të passhëm. Ose sigurohuni se ndryshorja SSH_AUTH_SOCK e mjedisit ekziston, ose caktoni për të një anashkalim. SSH Agent connection is working! Lidhja e Agjentit SSH funksionon! - - Use both agents - Përdoru të dy agjentët - ApplicationSettingsWidget @@ -169,6 +169,10 @@ Security Siguri + + This setting cannot be enabled when minimize on unlock is enabled. + Ky rregullim s’mund të aktivizohet, kur është aktivizuar “Minimizoje gjatë shkyçjes”. + Access error for config file %1 Gabim hyrjeje në kartelë formësimi %1 @@ -191,7 +195,7 @@ Follow style - + Ndiq stilin Monochrome @@ -203,7 +207,7 @@ Monochrome (dark) - Njëngjyrës (i errët) + Njëngjyrësh (i errët) Colorful @@ -213,21 +217,49 @@ You must restart the application to set the new language. Would you like to restart now? Që të caktoni gjuhën e re, duhet të rinisni aplikacionin. Do të donit të riniset tani? - - Reset Settings? - Të Rikthehen Rregullimet Te Parazgjedhjet? - - - Are you sure you want to reset all general and security settings to default? - Jeni i sigurt se doni të rikthehen te parazgjedhjet krejt rregullimet e përgjithshme dhe ato të sigurisë? - Select backup storage directory Përzgjidhni drejtori depozitë kopjeruajtjesh - This setting cannot be enabled when minimize on unlock is enabled. - Ky rregullim s’mund të aktivizohet, kur është aktivizuar “Minimizo gjatë shkyçjes”. + Confirm Reset + Ripohoni Kthimin te Parazgjedhja + + + Are you sure you want to reset all settings to default? + Jeni i sigurt se doni të kthehen krejt rregullimet te parazgedhjet? + + + Import KeePassXC Settings + Importo Rregullime KeePassXC + + + Failed to import settings from %1, not a valid settings file. + S’u arrit të importoheshin rregullime nga %1, s’është kartelë rregullimesh e vlefshme. + + + Export KeePassXC Settings + Eksporto Rregullime KeePassXC + + + Small + + + + Normal + + + + Medium + + + + Large + + + + Custom + @@ -258,7 +290,11 @@ Remember previously used databases - Mba mend baza të dhënash të mëparshme + Mbaj mend baza të dhënash të mëparshme + + + recent files + kartela së fundi Load previously open databases on startup @@ -266,7 +302,7 @@ Remember database key files and security dongles - + Mbaj mend kartela kyçesh baze të dhënash dhe marifetesh sigurie Check for updates at application startup once per week @@ -276,25 +312,6 @@ Include beta releases when checking for updates Kur kontrollohet për përditësime, përfshi hedhje beta në qarkullim - - On database unlock, show entries that - Gjatë shkyçjeje baze të dhënash, shfaq zëra që - - - have expired - On database unlock, show entries that... - kanë skaduar - - - days - On database unlock, show entries that will expire within %1 days - ditësh - - - will expire within - On database unlock, show entries that... - do të skadojnë brenda - File Management Administrim Kartelash @@ -319,22 +336,10 @@ Backup database file before saving Kopjeruani kartelën e bazës tuaj të të dhënave, përpara ruajtjes - - Backup destination - Vendmbërritje kopjeruajtjeje - - - Specifies the database backup file location. Occurrences of "{DB_FILENAME}" are replaced with the filename of the saved database without extension. {TIME:<format>} is replaced with the backup time, see https://doc.qt.io/qt-5/qdatetime.html#toString. <format> defaults to format string "dd_MM_yyyy_hh-mm-ss". - Përcakton vendndodhje kartele kopjeruajtjeje baze të dhënash. Hasje të “{DB_FILENAME}” zëvendësohen me emrin e kartelës së bazës së ruajtur të të dhënave, pa zgjatimin. {TIME:<format>} zëvendësohet me kohën e bërjes së kopjeruajtjes, shihni https://doc.qt.io/qt-5/qdatetime.html#toString. <format> parazgjedhje për formatim vargu “dd_MM_yyyy_hh-mm-ss”. - {DB_FILENAME}.old.kdbx {DB_FILENAME}.old.kdbx - - Choose... - Zgjidhni… - Use alternative saving method (may solve problems with Dropbox, Google Drive, GVFS, etc.) Përdorni metodë alternative ruajtje (mund të zgjidhë probleme me Dropbox, Google Drive, GVFS, etj.) @@ -369,7 +374,7 @@ Drop to background - + Lëre në sfond Favicon download timeout: @@ -377,7 +382,7 @@ Website icon download timeout in seconds - + Mbarim kohe shkarkimi ikonash sajtesh, në sekonda sec @@ -412,6 +417,10 @@ Toolbar button style: Stil butonash paneli: + + Show passwords in color + Shfaqi fjalëkalimet me ngjyra + Use monospaced font for notes Për shënime përdor shkronja Monospace @@ -446,11 +455,11 @@ Use entry title to match windows for global Auto-Type - + Përdor titull zëri për kërkim dritaresh me përputhjeje, për Vetë-shtypje globale Use entry URL to match windows for global Auto-Type - + Përdor URL zëri për kërkim dritaresh me përputhjeje, për Vetë-shtypje globale Always ask before performing Auto-Type @@ -498,12 +507,69 @@ Mbaje mend zërin e fundit të shtypur për: - recent files - kartela së fundi + On database unlock, show entries that will expire within + Kur shkyçet bazë të dhënash, shfaq zëra që do të skadojnë brenda - Show passwords in color - Shfaqi fjalëkalimet me ngjyra + On database unlock, show entries that will expire within + Kur shkyçet bazë të dhënash, shfaq zëra që do të skadojnë brenda + + + days + number of days warning for password expiration + ditësh + + + Destination format: + Format vendmbërritje: + + + <html><head/><body><p><span style=" font-weight:600;">{DB_FILENAME}</span> is replaced with the filename of the saved database without extension</p><p><span style=" font-weight:600;">{TIME:&lt;format&gt;}</span> is replaced with the specified time format (default: dd_MM_yyyy_hh-mm-ss)</p><p>See the User Guide for more details</p></body></html> + <html><head/><body><p><span style=" font-weight:600;">{DB_FILENAME}</span> zëvendësohet me emrin e kartelës të bazës së të dhënave të ruajtur, pa zgjatim</p><p><span style=" font-weight:600;">{TIME:&lt;format&gt;}</span> zëvendësohet me formatin e përcaktuar të kohës (parazgjedhje: dd_MM_yyyy_hh-mm-ss)</p><p>Për më tepër hollësi, shihni Udhërrëfyes Përdoruesi</p></body></html> + + + Choose folder... + Zgjidhni dosje… + + + Show confirmation before moving entries to recycle bin + Shfaq hap ripohimi para kalimit të zërave te koshi i riciklimeve + + + Copy data on double clicking field in entry view + Me dyklikim të një fushe, te pamja e zërit, kopjo të dhënat + + + Show toolbar + Shfaq panelin + + + Show the menu bar by pressing the Alt key + Shfaq shtyllë menuje, kur shtypet tasti Alt + + + Show menubar + Shfaq shtyllë menuje + + + Import settings… + Importoni rregullime… + + + Export settings… + Eksportoni rregullime… + + + Open browser on double clicking URL field in entry view + Me dyklikim të fushës së URL-së, te pamja e zërit, hap shfletuesin + + + Font size: + + + + Font size selection + @@ -514,7 +580,7 @@ Database lock timeout seconds - + Sekonda mbarimi kohe kyçjeje baze të dhënash sec @@ -536,7 +602,7 @@ Clipboard clear seconds - + Sekonda spastrimi baze të dhënash Lock databases after inactivity of @@ -548,23 +614,19 @@ Enable database quick unlock (Touch ID / Windows Hello) - + Aktivizo shkyçje të shpejtë baze të dhënash (Touch ID / Windows Hello) Lock databases when session is locked or lid is closed - + Kyçi bazat e të dhënave, kur kyçet sesioni, ose mbyllet kapaku i portativit Lock databases after minimizing the window Kyçi bazat e të dhënave pas minimizimit të dritares - - Require password repeat when it is visible - - Hide passwords when editing them - + Fshihi fjalëkalimet, kur përpunohen Use placeholder for empty password fields @@ -572,19 +634,7 @@ Hide passwords in the entry preview panel - - - - Hide entry notes by default - Si parazgjedhje, fshihi shënimet mbi zëra - - - Move entries to recycle bin without confirmation - - - - Enable double click to copy the username/password entry columns - + Fshihi fjalëkalimet, te paneli i paraparjes së zërave Privacy @@ -596,14 +646,26 @@ Hide TOTP in the entry preview panel - + Fshih TOTP, te paneli i paraparjes së zërave + + + Lock databases when switching user + Kyçi bazat e të dhënave, kur ndërrohet përdorues + + + Lock Options + Mundësi Kyçjeje + + + Hide notes in the entry preview panel + Fshihi shënimet, te paneli i paraparjes së zërave AutoType The requested Auto-Type sequence cannot be used due to an error: - + Sekuenca e kërkuar për Vetë-shtypje s’mund të përdoret, për shkak të një gabimi: Auto-Type Error @@ -615,53 +677,40 @@ KeePassXC requires the Accessibility permission in order to perform entry level Auto-Type. If you already granted permission, you may have to restart KeePassXC. - + KeePassXC-ja lyp leje Përdorimi Nga Persona Me Aftësi të Kufizuara, që të mund të kryejë Vetë-Shtypje të nivelit elementar. Nëse e keni akorduar tashmë lejen, mund t’ju duhet të rinisni KeePassXC-në. KeePassXC requires the Accessibility and Screen Recorder permission in order to perform global Auto-Type. Screen Recording is necessary to use the window title to find entries. If you already granted permission, you may have to restart KeePassXC. - + KeePassXC-ja lyp leje Përdorimi Nga Persona Me Aftësi të Kufizuara dhe Regjistruesi Ekrani, që të mund të kryejë Vetë-Shtypje globale. Regjistrimi i Ekranit është i nevojshëm për të përdorur titullin e dritares për të gjetur zëra. Nëse e keni akorduar tashmë lejen, mund t’ju duhet të rinisni KeePassXC-në. Invalid entry provided - + U dha zë i pavlefshëm Bracket imbalance detected, found extra { or } - + U pikas kllapë e pambyllur, u gjet { ose } ekstra Too many repetitions detected, max is %1: %2 - + U pikasën shumë përsëritje, maksimumi është %1: %2 Very slow key press detected, max is %1: %2 - + U pikas shtypje shumë e ngadaltë tastesh, maksimumi është %1: %2 Very long delay detected, max is %1: %2 - - - - Invalid conversion type: %1 - - - - Invalid conversion syntax: %1 - - - - Invalid regular expression syntax %1 -%2 - - - - Invalid placeholder: %1 - Vendmbajtëse e pavlefshme: %1 + U pikas shtypje shumë e gjatë tastesh, maksimumi është %1: %2 Entry does not have attribute for PICKCHARS: %1 Zëri s’ka atribut për PICKCHARS: %1 + + Invalid placeholder: %1 + Vendmbajtëse e pavlefshme: %1 + AutoTypeAssociationsModel @@ -703,32 +752,32 @@ AutoTypePlatformX11 - - Trying to send invalid keysym. - - Sequence aborted: Caps Lock is on - + Sekuenca u ndërpre: Caps Lock është aktiv Sequence aborted: Modifier keys held by user - + Sekuenca u ndërpre: Taste ndryshues shtypur nga përdoruesi Unable to get valid keycode for key: - + S’arrihet të merret kod i vlefshëm tasti për tastin: + + + Trying to send invalid keyboard symbol. + Po provohet të dërgohet simbol i pavlefshëm tastiere. AutoTypeSelectDialog Auto-Type - KeePassXC - + Vetë-Shtypje - KeePassXC Double click a row to perform Auto-Type or find an entry using the search: - + Dyklikoni mbi një rresht, që të kryhet Vetë-Shtypje, ose gjeni një zë duke përdorur kërkimin: <p>You can use advanced search queries to find any entry in your open databases. The following shortcuts are useful:<br/> @@ -737,7 +786,12 @@ Ctrl+1 - Type username<br/> Ctrl+2 - Type password<br/> Ctrl+3 - Type TOTP<br/> Ctrl+4 - Use Virtual Keyboard (Windows Only)</p> - + <p>Mund të përdorni kërkim të thelluar, për të gjetur çfarëdo zëri në bazat tuaja të hapura të të dhënave. Janë të dobishme shkurtoret vijuese:<br/> +Ctrl+F - Hap/Mbyll kërkim në bazë të dhënash<br/> +Ctrl+1 - Shtypni emër përdoruesi<br/> +Ctrl+2 - Shtypni fjalëkalim<br/> +Ctrl+3 - Shtypni TOTP<br/> +Ctrl+4 - Përdorni Tastierë Virtuale (Vetëm në Windows)</p> Search all open databases @@ -757,15 +811,15 @@ Ctrl+4 - Use Virtual Keyboard (Windows Only)</p> Type {USERNAME} - + Shtypni {EMËR_PËRDORUESI} Type {PASSWORD} - + Shtypni {FJALËKALIM} Type {TOTP} - + Shtypni {TOTP} Copy Username @@ -788,15 +842,15 @@ Ctrl+4 - Use Virtual Keyboard (Windows Only)</p> BrowserAccessControlDialog KeePassXC - Browser Access Request - + KeePassXC - Kërkesë Për Hyrje Nga Shfletues %1 is requesting access to the following entries: - + %1 po kërkon të hyjë te zërat vijuese: Remember access to checked entries - + Mbaj mend hyrje te zërat e me shenjë Remember @@ -818,13 +872,13 @@ Ctrl+4 - Use Virtual Keyboard (Windows Only)</p> Disable for this site Çaktivizoje për këtë sajt + + Undo + Zhbëje + BrowserEntrySaveDialog - - KeePassXC-Browser Save Entry - - Ok Ok @@ -839,22 +893,81 @@ Please select the correct database for saving credentials. Keni të hapura disa baza të dhënash. Ju lutemi, përzgjidhni bazën e saktë të të dhënave për ruajtje kredencialesh. + + KeePassXC - Select Database + KeePassXC - Përzgjidhni Bazë të Dhënash + + + + BrowserPasskeysConfirmationDialog + + Cancel + Anuloje + + + Update + Përditësoje + + + Authenticate + Bëni mirëfilltësimin + + + Register new + Regjistroni të ri + + + Register + Regjistroje + + + Timeout in <b>%n</b> seconds... + Mbarim kohe në <b>%n</b> sekondë…Mbarim kohe në <b>%n</b> sekonda… + + + Relying Party: %1 + + + + Username: %1 + Emër përdoruesi: %1 + + + KeePassXC - Passkey credentials + KeePassXC - Kredenciale kyçkalimi + + + Add to existing entry + Shtoje te zë ekzistues + + + Existing passkey found. +Do you want to register a new passkey for: + U gjet kyçkalim ekzistues. +Doni të regjistrohet një kyçkalim i ri për: + + + Select the existing passkey and press Update to replace it. + Përzgjidhni kyçkalimin ekzistues dhe shtypni Përditësoje, që të zëvendësohet. + + + Authenticate passkey credentials for: + Bëj mirëfilltësimin e kredencialeve të kodkalimit për: + + + Do you want to register a passkey for: + Doni të regjistrohet një kyçkalim për: + BrowserService - - KeePassXC: Create a new group - KeePassXC: Krijoni një grup të ri - A request for creating a new group "%1" has been received. Do you want to create this group? - - - - KeePassXC: New key association request - + Është marrë një kërkesë për krijimin e një grupi të ri “%1”. +Doni të krijohet ky grup? + You have received an association request for the following database: @@ -862,82 +975,87 @@ Do you want to create this group? Give the connection a unique name or ID, for example: chrome-laptop. - + Keni marrë një kërkesë përshoqërimi për bazën vijuese të të dhënave: +%1 + +Jepini lidhje një emër ose ID unike, për shembull: +chrome-laptop. Save and allow access Ruaje dhe lejo hyrje - - KeePassXC: Overwrite existing key? - KeePassXC: Të mbishkruhet kyçi ekzistues? - A shared encryption key with the name "%1" already exists. Do you want to overwrite it? Ka tashmë një kyç të përbashkët fshehtëzimi me emrin “%1”. Doni të mbishkruhet? - - KeePassXC: Update Entry - KeePassXC: Përditëso Zërin - Do you want to update the information in %1 - %2? Doni të përditësohet informacioni në %1 - %2 kb? - - KeePassXC: Delete entry - KeePassXC: Fshije zërin - A request for deleting entry "%1" has been received. Do you want to delete the entry? - + Është marrë një kërkesë për fshirjen e zërit “%1”. +Doni të fshihet zëri? + - Converting attributes to custom data… - Po shndërrohen atribute në të dhëna vetjake… + %1 (Passkey) + %1 (Kyçkalim) - Abort - Ndërprite + KeePassXC - Create a new group + KeePassXC - Krijoni një grup të ri - KeePassXC: Converted KeePassHTTP attributes - + Disable + Çaktivizoje - Successfully converted attributes from %1 entry(s). -Moved %2 keys to custom data. - - - - Successfully moved %n keys to custom data. - + KeePassXC - Overwrite existing key? + KeePassXC - Të mbishkruhet kyçi ekzistues? - KeePassXC: No entry with KeePassHTTP attributes found! - + KeePassXC - Update Entry + KeePassXC - Përditësoje Zërin - The active database does not contain an entry with KeePassHTTP attributes. - + KeePassXC - Delete entry + KeePassXC - Fshije zërin - Don't show this warning again - Mos e shfaq më këtë sinjalizim + KeePassXC - New key association request + KeePassXC - Kërkesë për përshoqërim të ri kyçi - KeePassXC: Legacy browser integration settings detected - + Passkey + Kyçkalim - Your KeePassXC-Browser settings need to be moved into the database settings. -This is necessary to maintain your current browser connections. -Would you like to migrate your existing settings now? - + KeePassXC - Passkey credentials + KeePassXC - Kredenciale kyçkalimi + + + Register a new passkey to this entry: + Regjistroni një kyçkalim të ri për këtë zë: + + + KeePassXC - Update passkey + KeePassXC - Përditësoni kyçkalim + + + Entry already has a passkey. +Do you want to overwrite the passkey in %1 - %2? + Zëri ka tashmë një kyçkalim. +Doni të mbishkruhet kyçkalimi te %1 - %2? + + + Register + Regjistroje @@ -948,7 +1066,7 @@ Would you like to migrate your existing settings now? This is required for accessing your databases with KeePassXC-Browser - + Kjo është e domosdoshme për të hyrë në bazat tuaja të të dhënave me Shfletuesin KeePassXC Enable browser integration @@ -958,13 +1076,9 @@ Would you like to migrate your existing settings now? General Të përgjithshme - - Browsers installed as snaps are currently not supported. - - Enable integration for these browsers: - + Aktivizo integrim për këta shfletues: Vivaldi @@ -1001,40 +1115,40 @@ Would you like to migrate your existing settings now? Request to unlock the database if it is locked - + Kërko të shkyçet baza e të dhënave, nëse është e kyçur Only entries with the same scheme (http://, https://, …) are returned. - + Sillen vetëm zëra me të njëjtën skemë (http://, https://, …). Match URL scheme (e.g., https://example.com) - + Kërko përkim me skemë URL-je (p.sh., https://example.com) Only returns the best matches for a specific URL instead of all entries for the whole domain. - + Sillen vetëm përkimet më të mira për një URL të dhënë, në vend se krejt zërat për përkatësinë si e tërë. Return only best-matching credentials - + Sill vetëm kredencialet që përputhen më mirë Returns expired credentials. String [expired] is added to the title. - + Sjell kredenciale të skaduara. Te titulli shtohet vargu [expired]. Allow returning expired credentials - + Lejo sjellje kredencialesh të skaduara All databases connected to the extension will return matching credentials. - + Krejt bazat e të dhënave të lidhura me zgjerimin do të sjellin kredenciale me përkim. Search in all opened databases for matching credentials Credentials mean login data requested via browser extension - + Kërko në krejt bazat e hapura të të dhënave për kredenciale me përkim Advanced @@ -1043,33 +1157,33 @@ Would you like to migrate your existing settings now? Never ask before accessing credentials Credentials mean login data requested via browser extension - + Mos pyet kurrë para hyrjes në kredenciale Never ask before updating credentials Credentials mean login data requested via browser extension - + Mos pyet kurrë para përditësimit të kredencialeve Do not ask permission for HTTP Basic Auth An extra HTTP Basic Auth setting - + Mos kërko leje për Mirëfillësim HTTP Elementar Automatically creating or updating string fields is not supported. - + Nuk mbulohet krijim apo përditësim i automatizuar i fushave të vargjeve. Return advanced string fields which start with "KPH: " - + Sill fusha të thelluara vargjesh që fillojnë me “KPH: ” Don't display the popup suggesting migration of legacy KeePassHTTP settings. - + Mos e shfaq flluskën që sugjeron migrim të rregullimeve të dikurshme për KeePassHTTP. Do not prompt for KeePassHTTP settings migration. - + Mos pyet për migrim rregullimesh për KeePassHTTP. Updates KeePassXC or keepassxc-proxy binary path automatically to native messaging scripts on startup. @@ -1081,20 +1195,20 @@ Would you like to migrate your existing settings now? Use a custom proxy location if you installed a proxy manually. - + Përdorni një vendndodhje vetjake ndërmjetësi, nëse instaluat dorazi një ndërmjetës. Use a custom proxy location: Meant is the proxy for KeePassXC-Browser - + Përdor një vendndodhje vetjake ndërmjetësi: Custom proxy location field - + Fushë vendndodhjeje vetjake ndërmjetësi Browser for custom proxy file - + Shfletues për kartelë vetjake ndërmjetësi Browse… @@ -1103,7 +1217,7 @@ Would you like to migrate your existing settings now? Use a custom browser configuration location: - + Përdor një vendndodhje vetjake formësimi shfletuesi: Browser type: @@ -1119,31 +1233,19 @@ Would you like to migrate your existing settings now? Custom browser location field - + Fushë vendndodhjeje vetjake shfletuesi Browse for custom browser path - + Shfletoni për shteg shfletuesi vetjak Custom extension ID: - + ID zgjerimi vetjak: Custom extension ID - - - - Due to Snap sandboxing, you must run a script to enable browser integration.<br />You can obtain this script from %1 - - - - KeePassXC-Browser is needed for the browser integration to work. <br />Download it for %1 and %2 and %3. %4 - - - - Please see special instructions for browser extension use below - + ID zgjerimi vetjak Executable Files @@ -1155,26 +1257,50 @@ Would you like to migrate your existing settings now? Select custom proxy location - + Përzgjidhni vendndodhje ndërmjetësi vetjak Select native messaging host folder location - <b>Warning:</b> Only adjust these settings if necessary. + Allow keepassxc-proxy to list all entries with their title, URL and UUID in connected databases. + + Allow limited access to all entries in connected databases (ignores site access restrictions) + + + + <b>Warning:</b> Only adjust these settings if necessary. + <b>Kujdes:</b> Këto rregullime përimtojini vetëm nëse është e nevojshme. + The custom proxy location does not exist. - + Vendndodhja e ndërmjetësit vetjak s’ekziston. <b>Error:</b> The custom proxy location does not exist. Correct this in the advanced settings tab. - + <b>Gabim:</b> Vendndodhja e ndërmjetësit vetjak s’ekziston. Ndreqeni këtë te skeda e rregullimeve të mëtejshme. <b>Error:</b> The installed proxy executable is missing from the expected location: %1<br/>Please set a custom proxy location in the advanced settings or reinstall the application. + <b>Gabim:</b> I ekzekutueshmi për ndërmjetësin e instaluar mungon te vendndodhja e pritur: %1<br/>Ju lutemi, caktoni një vendndodhje ndërmjetësi vetjak, te rregullimet e mëtejshme, ose riinstaloni aplikacionin. + + + Allows using insecure http://localhost with passkeys for testing purposes. + Lejon përdorim http://localhost jo të siguruar me kodkalime, për qëllime testimi. + + + Allow using localhost with passkeys + Lejo përdorim localhost-i me kodkalime + + + KeePassXC-Browser is needed for the browser integration to work. <br />Download it for %1 and %2 and %3. + Që të funksionojë integrimi i shfletuesit, është i nevojshëm Shfletuesi KeePassXC. <br />Shkarkojeni për %1 dhe %2 dhe %3. + + + Browsers installed using Snap or Flatpak are not supported with exception to Firefox installed using Snap. @@ -1186,7 +1312,7 @@ Would you like to migrate your existing settings now? Append ' - Clone' to title - ShtoAppend ' - Clone' te titulli + Shto “ - Clone” te titulli Replace username and password with references @@ -1199,14 +1325,6 @@ Would you like to migrate your existing settings now? CsvImportWidget - - Import CSV fields - Importoni fusha CSV - - - filename - emër kartele - size, rows, columns madhësi, rreshta, shtylla @@ -1285,11 +1403,11 @@ Would you like to migrate your existing settings now? Header lines skipped - + U anashkaluan rreshta kryesh Number of header lines to discard - + Numër rreshtash kryesh për t’u anashkaluar First line has field names @@ -1309,56 +1427,49 @@ Would you like to migrate your existing settings now? Not Present - + Jo i Pranishëm Column %1 Shtylla %1 - - Imported from CSV file - Importuar prej kartele CSV - - - Original data: - Të dhëna origjinale: - - - Error(s) detected in CSV file! - Gabim(e) i pikasur në kartelë CSV! - [%n more message(s) skipped] [%n mesazh tjetër i anashkaluar][%n mesazhe të tjerë të anashkaluar] - Error - Gabim + Failed to parse CSV file: %1 + S’u arrit të analizohej kartelë CSV: %1 - CSV import: writer has errors: -%1 - Importim CSV: shkrimi ka gabime: -%1 + Imported from CSV file: %1 + Importuar nga kartelë CSV: %1 + + + No Title Selected + S’u Përzgjodh Titull + + + No title column was selected, entries will be hard to tell apart. +Are you sure you want to import? + S’u përzgjodh shtyllë titujsh, do të jetë e vështirë të dallohen zërat njëri nga tjetri. +Jeni i sigurt se doni të importohet? + + + Tags + Etiketa CsvParserModel - - %1, %2, %3 - file info: bytes, rows, columns - %1, %2, %3 - - - %n byte(s) - %n bajt(e)%n bajt(e) - %n row(s) - %n rresht(a)%n rresht(a) + CSV row count + %n rresht%n rreshta %n column(s) + CSV column count %n shtyllë%n shtylla @@ -1383,7 +1494,7 @@ Would you like to migrate your existing settings now? Could not save, database does not point to a valid file. - + S’u ruajt dot, baza e të dhënave s’tregon ndonjë kartelë të vlefshme. Database save is already in progress. @@ -1391,24 +1502,33 @@ Would you like to migrate your existing settings now? Could not save, database has not been initialized! - + S’u ruajt dot, baza e të dhënave s’është gatitur! Database file has unmerged changes. - + Kartela e bazës së të dhënave ka ndryshime të papërziera. %1 Backup database located at %2 - + %1 +Kopjeruaj bazë të dhënash që gjendet te %2 Key not transformed. This is a bug, please report it to the developers. - + Kyçi s’u shndërrua. Kjo është një e metë, ju lutemi, njoftojuani zhvilluesve. Recycle Bin - Kosh Hedhurinash + Kosh Riciklimesh + + + Database file read error. + + + + No file path was provided. + @@ -1432,29 +1552,9 @@ Backup database located at %2 Password field Fushë fjalëkalimi - - Enter Additional Credentials (if any): - Jepni Kredenciale Shtesë (në pastë): - - - Key File: - Kartelë Kyçi: - - - Key file help - Ndihmë për kartela kyçesh - Hardware key slot selection - - - - Hardware Key: - Kyç Hardware: - - - Hardware key help - Ndihmë për kyçe hardware + Përzgjedhje vendi kyçi hardware Key file to unlock the database @@ -1468,14 +1568,6 @@ Backup database located at %2 Browse… Shfletoni… - - Refresh hardware tokens - - - - Refresh - Rifreskoje - Unlock Database Shkyçe Bazën e të Dhënave @@ -1490,7 +1582,7 @@ Backup database located at %2 Please present or touch your YubiKey to continue… - + Ju lutemi, që të vazhdohet, paraqitni, ose prekni YubiKey-në tuaj… Database Version Mismatch @@ -1504,7 +1596,14 @@ You can try to open it anyway, but it may be incomplete and saving any changes may incur data loss. We recommend you update your KeePassXC installation. - + Gjasat janë që baza e të dhënave që po provoni të hapni +të qe krijuar nga një version më i ri i KeePassXC-së. + +Mund të provoni ta hapni, sido që të jetë, por mund të +jetë e paplotë dhe ruajtja e çfarëdo ndryshimesh mund +të sjellë humbje të dhënash. + +Rekomandojmë të përditësoni instalimin tuaj të KeePassXC-së. Open database anyway @@ -1516,26 +1615,25 @@ We recommend you update your KeePassXC installation. Unlock failed and no password given - + Shkyçja dështoi dhe s’u dha fjalëkalim Unlocking the database failed and you did not enter a password. Do you want to retry with an "empty" password instead? To prevent this error from appearing, you must go to "Database Settings / Security" and reset your password. - + Shkyçja e bazës së të dhënave dështoi dhe s’dhatë fjalëkalim. +Në vend të kësaj, doni të riprovohet me një fjalëkalim “të zbrazët”? + +Që të pengoni shfaqjen e këtij gabimi, duhet të kaloni te “Rregullime baze të dhënash / Siguri” dhe të ricaktoni fjalëkalimin tuaj. Retry with empty password Riprovo me fjalëkalim të zbrazët - - Failed to authenticate with Touch ID - S’u arrit të bëhej mirëfilltësim me Touch ID - Failed to open key file: %1 - S’u arrit të hapej kartelë kyçesh: %1 + S’u arrit të hapej kartelë kyç: %1 Old key file format @@ -1543,7 +1641,7 @@ To prevent this error from appearing, you must go to "Database Settings / S You are using an old key file format which KeePassXC may<br>stop supporting in the future.<br><br>Please consider generating a new key file by going to:<br><strong>Database &gt; Database Security &gt; Change Key File.</strong><br> - + Po përdorni një format të vjetër kartelash kyçesh, të cilin KeePassXC-ja mund <br>të reshtë ta mbulojë në të ardhmen.<br><br>Ju lutemi, shihni mundësinë e prodhimit të një kartelë të re kyçi, duke kaluar te:<br><strong>Bazë të dhënash &gt; Siguri Baze të Dhënash &gt; Ndryshoni Kartelë Kyç.</strong><br> Don't show this warning again @@ -1563,44 +1661,70 @@ To prevent this error from appearing, you must go to "Database Settings / S Cannot use database file as key file - - - - You cannot use your database file as a key file. -If you do not have a key file, please leave the field empty. - - - - Detecting hardware keys… - Po pikasen kyçe hardware… - - - No hardware keys detected - S’u pikasën kyçe hardware - - - Select hardware key… - Përzgjidhni kyç hardware… - - - <p>In addition to a password, you can use a secret file to enhance the security of your database. This file can be generated in your database's security settings.</p><p>This is <strong>not</strong> your *.kdbx database file!<br>If you do not have a key file, leave this field empty.</p><p>Click for more information…</p> - - - - <p>You can use a hardware security key such as a <strong>YubiKey</strong> or <strong>OnlyKey</strong> with slots configured for HMAC-SHA1.</p> -<p>Click for more information…</p> - + S’mund të përdoret kartelë baze të dhënash si kartelë kyçi authenticate to access the database - + që të hyni në bazën e të dhënave, bëni mirëfilltësimin - Failed to authenticate with Windows Hello: %1 - + Failed to authenticate with Quick Unlock: %1 + S’u arri të bëhej mirëfilltësimi me Shkyçje të Shpejtë: %1 - Windows Hello setup was canceled or failed. Quick unlock has not been enabled. + Select Key File: + Përzgjidhni Kartelë Kyçi: + + + <p>In addition to a password, you can use a secret file to enhance the security of your database. This file can be generated in your database's security settings.</p><p>This is <strong>not</strong> your *.kdbx database file!</p> + <p>Tej një fjalëkalimi, mund të përdorni një kartelë të fshehtë për të thelluar sigurinë e bazës suaj të të dhënave. Kjo kartelë mund të prodhohet që nga rregullimet e sigurisë së bazës suaj të të dhënave.</p><p>Kjo <strong>nuk</strong> është kartela juaj *.kdbx e bazës së të dhënave!</p> + + + Use hardware key [Serial: %1] + Përdor kyç hardware [Serial: %1] + + + Use hardware key + Përdor kyç hardware + + + Your database file is NOT a key file! +If you don't have a key file or don't know what that is, you don't have to select one. + Kartela juaj e bazës së të dhënave NUK është kartelë kyçi! +Nëse s’keni një kartelë kyçi, ose s’e dini se ç’është një e tillë, s’ju duhet të përzgjidhni një. + + + KeePassXC database file selected + U përzgjodh kartelë baze të dhënash KeePassXC + + + The file you selected looks like a database file. +A database file is NOT a key file! + +Are you sure you want to continue with this file?. + Kartela që përzgjodhët, duket si kartelë baze të dhënash. +Një kartelë baze të dhënash NUK është kartelë kyçi! + +Jeni i sigurt se doni të vazhdohet me këtë kartelë? + + + No hardware keys found. + S’u gjet kyç hardware. + + + Refresh Hardware Keys + Rifresko Kyçe Hardware + + + Click to add a key file. + Klikoni që të shtohet një kartelë kyç. + + + <a href="#" style="text-decoration: underline">I have a key file</a> + <a href="#" style="text-decoration: underline">Kam një kartelë kyç</a> + + + Hardware keys found, but no slots are configured. @@ -1613,10 +1737,6 @@ If you do not have a key file, please leave the field empty. DatabaseSettingsDialog - - Advanced Settings - Rregullime të Mëtejshme - General Të përgjithshme @@ -1641,6 +1761,22 @@ If you do not have a key file, please leave the field empty. Maintenance Mirëmbajtje + + KeeShare + KeeShare + + + Secret Service Integration + Integrim Shërbimi të Fshehtash + + + Remote Sync + Njëkohësim i Largët + + + Database Settings: %1 + Rregullime Baze të Dhënash: %1 + DatabaseSettingsWidgetBrowser @@ -1648,25 +1784,17 @@ If you do not have a key file, please leave the field empty. KeePassXC-Browser settings Rregullime për KeePassXC-Browser - - Convert KeePassHTTP data - Shndërroni të dhëna KeePassHTTP - - - Convert legacy KeePassHTTP attributes to KeePassXC-Browser compatible custom data - - - - Refresh database root group ID - - Disconnect all browsers Shkëputi krejt shfletuesit Forget all site-specific settings on entries - + Harro krejt rregullimet specifike për sajte, te zërat + + + Refresh database root group ID + Rifresko ID grupi rrënjë baze të dhënash Stored keys @@ -1674,7 +1802,7 @@ If you do not have a key file, please leave the field empty. Stored browser keys - + Kyçe shfletuesi të depozituar Remove selected key @@ -1691,7 +1819,8 @@ If you do not have a key file, please leave the field empty. Do you really want to delete the selected key? This may prevent connection to the browser plugin. - + Doni vërtet të fshihet kyçi i përzgjedhur? +Kjo mund të pengojë lidhjen me shtojcën e shfletuesit. Key @@ -1712,28 +1841,22 @@ This may prevent connection to the browser plugin. Do you really want to disconnect all browsers? This may prevent connection to the browser plugin. - - - - KeePassXC: No keys found - KeePassXC: S’u gjetën kyçe + Doni vërtet të shkëputen krejt shfletuesit? +Kjo mund të pengojë lidhjen me shtojcën e shfletuesit. No shared encryption keys found in KeePassXC settings. - - - - KeePassXC: Removed keys from database - + Te rregullimet e KeePassXC-së s’u gjetën kyçe të përbashkët fshehtëzimi. Successfully removed %n encryption key(s) from KeePassXC settings. - + U hoq me sukses %n kyç fshehtëzimi që nga rregullimet e KeePassXC-së.U hoqën me sukses %n kyçe fshehtëzimi që nga rregullimet e KeePassXC-së. Do you really want forget all site-specific settings on every entry? Permissions to access entries will be revoked. - + Doni vërtet të harrohen krejt rregullimet specifike për sajte, në çdo zë? +Do të shfuqizohen leje për përdorim të zërave. Removing stored permissions… @@ -1743,30 +1866,13 @@ Permissions to access entries will be revoked. Abort Ndërprite - - KeePassXC: Removed permissions - KeePassXC: U hoqën leje - Successfully removed permissions from %n entry(s). - - - - KeePassXC: No entry with permissions found! - KeePassXC: S’u gjet zë me leje! + U hoq me sukses leje nga %n zë.U hoqën me sukses leje nga %n zëra. The active database does not contain an entry with permissions. - - - - Move KeePassHTTP attributes to custom data - - - - Do you really want to convert all legacy browser integration data to the latest standard? -This is necessary to maintain compatibility with the browser plugin. - + Baza aktive e të dhënave s’përmban zë me leje. Refresh database ID @@ -1775,7 +1881,28 @@ This is necessary to maintain compatibility with the browser plugin. Do you really want refresh the database ID? This is only necessary if your database is a copy of another and the browser extension cannot connect. - + Doni vërtet të rifreskohet ID-ja e bazës së të dhënave? +Kjo është e nevojshme vetëm nëse baza juaj e të dhënave është një kopje e një tjetre dhe zgjerimi i shfletuesit s’bën dot lidhjen. + + + Convert legacy KeePassHTTP attributes to KeePassXC-Browser compatible custom data + Shndërroni atribute KeePassHTTP të dikurshëm në të dhëna vetjake të përputhshme me KeePassXC-Browser + + + No keys found + S’u gjetën kyçe + + + Removed keys from database + U hoqën kyçe nga baza e të dhënave + + + Removed permissions + U hoqën leje + + + No entry with permissions found! + S’u gjet zë me leje! @@ -1816,6 +1943,18 @@ Jeni i sigurt se doni të vazhdohet pa një fjalëkalim? Failed to change database credentials S’u arrit të ndryshohen kredenciale baze të dhënash + + Weak password + Fjalëkalim i dobët + + + This is a weak password! For better protection of your secrets, you should choose a stronger password. + Ky është një fjalëkalim i dobët! Për mbrojtje më të mirë të të fshehtave tuaja, duhet të zgjidhni një fjalëkalim më të fortë. + + + The provided password does not meet the minimum quality requirement. + Fjalëkalimi i dhënë s’plotëson domosdoshmëritë minimum për cilësinë. + DatabaseSettingsWidgetEncryption @@ -1823,21 +1962,13 @@ Jeni i sigurt se doni të vazhdohet pa një fjalëkalim? Decryption Time: Kohë Shfshehtëzimi: - - Change existing decryption time - Ndryshoni kohën ekzistuese të shfshehtëzimit - - - Change - Ndryshojeni - Decryption time in seconds Kohë shfshehtëzimi në sekonda Higher values offer more protection, but opening the database will take longer. - Vlera më të mëdha ofrojnë më tepër mbrojtje, por hapja e bazës së të dhënave do të zgjasë më shumë + Vlera më të mëdha ofrojnë më tepër mbrojtje, por hapja e bazës së të dhënave do të zgjasë më shumë. Database format: @@ -1857,7 +1988,7 @@ Jeni i sigurt se doni të vazhdohet pa një fjalëkalim? Encryption Algorithm: - Algoritëm Ffshehtëzimi: + Algoritëm Fshehtëzimi: Encryption algorithm @@ -1911,11 +2042,6 @@ Jeni i sigurt se doni të vazhdohet pa një fjalëkalim? KDBX 3 KDBX 3 - - unchanged - Database decryption time is unchanged - - Number of rounds too high Key transformation rounds @@ -1968,6 +2094,18 @@ Nëse mbani këtë numër, baza juaj e të dhënave s’do të mbrohet nga sulme Threads for parallel execution (KDF settings) rrjedhë rrjedha + + Encryption Settings: + Rregullime Fshehtëzimi: + + + Basic + Elementare + + + Advanced + Të mëtejshme + DatabaseSettingsWidgetFdoSecrets @@ -1985,7 +2123,7 @@ Nëse mbani këtë numër, baza juaj e të dhënave s’do të mbrohet nga sulme Enable Secret Service to access these settings. - + Aktivizo hyrjen e Shërbimit të Fshehtë te këto rregullime. @@ -2024,11 +2162,11 @@ Nëse mbani këtë numër, baza juaj e të dhënave s’do të mbrohet nga sulme Maximum number of history items per entry - + Numër maksimum objektesh historiku për zë Maximum size of history per entry - + Madhësi maksimum historiku për zë MiB @@ -2036,7 +2174,7 @@ Nëse mbani këtë numër, baza juaj e të dhënave s’do të mbrohet nga sulme Use recycle bin - Përdor kosh hedhurinash + Përdor kosh riciklimesh Additional Database Settings @@ -2048,12 +2186,13 @@ Nëse mbani këtë numër, baza juaj e të dhënave s’do të mbrohet nga sulme Delete Recycle Bin - Fshi Kosh Hedhurinash + Fshi Kosh Riciklimesh Do you want to delete the current recycle bin and all its contents? This action is not reversible. - + Doni të fshihet koshi i tanishëm i riciklimeve dhe krejt lënda e tij? +Ky veprim s’është i prapakthyeshëm. (old) @@ -2064,29 +2203,102 @@ This action is not reversible. the oldest history items of an entry will be removed such that only the specified amount of entries remain at most. - + Kur ruhet ky rregullim, ose përpunohet një zë +objektet më të vjetër të historikut të një zëri +do të hiqen, që e shumta të mbetet vetëm sasia + e përcaktuar e zërave. Limit the amount of history items per entry to: - + Kufizoje sasinë e objekteve të historikut për zë në: When saving this setting or editing an entry the oldest history items of an entry will be removed such that the remaining history items add up to the specified amount at most. - + Kur ruhet ky rregullim, ose përpunohet një zë +objektet më të vjetër të historikut të një zëri +do të hiqen, që objektet e mbetur te historiku +të jenë e shumta deri sa sasia e përcaktuar. Limit the total size of history items per entry to: - + Kufizoje sasinë e objekteve të historikut gjithsej për zë në: Move entries to a recycle bin group instead of deleting them from the database. Entries deleted from the recycle bin are removed from the database. - + Kaloji zërat te një grup koshi riciklimi +në vend se t’i fshish nga baza e të dhënave. +Zërat e fshirë nga koshi i riciklimeve +hiqen nga baza e të dhënave. + + + Autosave delay since last change + Vonesë vetëruajtje që nga ndryshimi i fundit + + + Autosave delay + Vonesë vetëruajtjeje + + + Autosave delay since last change in minutes + Vonesë vetëruajtje që nga ndryshimi i fundit, në minuta + + + min + min + + + Autosave delay since last change checkbox + Vonesë vetëruajtje që nga ndryshimi i fundit, kutizë + + + Public Database Metadata + Tejtëdhëna Baze të Dhënash Publike + + + Warning: the following settings are not encrypted. + Kujdes: rregullimet vijuese s’janë të fshehtëzuara. + + + Display name: + Emër në ekran: + + + Publically visible display name used on the unlock dialog + Emër në ekran i dukshëm publikisht, i përdorur te dialogu i shkyçjeve + + + Database public display name + Emër publik në ekran baze të dhënash + + + Display color: + Ngjyrë ekrani: + + + Publically visible color used on the unlock dialog + Ngjyrë e dukshme publikisht, e përdorur te dialogu i shkyçjeve + + + Database public display color chooser + Zgjedhës ngjyre shfaqjeje publike baze të dhënash + + + Clear + Spastroji + + + Display icon: + Ikonë shfaqjeje: + + + Select Database Icon + Përzgjidhni Ikonë Baze të Dhënash @@ -2183,6 +2395,129 @@ removed from the database. Fushë përshkrimi baze të dhënash + + DatabaseSettingsWidgetRemote + + Sync Commands + Urdhra njëkohësimi + + + Remove + Hiqe + + + Command Settings + Rregullime Urdhri + + + Name + Emër + + + Save + Ruaje + + + Download + Shkarkoje + + + Command: + Urdhër: + + + Download command field + Fushë urdhri shkarkimi + + + e.g.: "sftp user@hostname" or "scp user@hostname:DatabaseOnRemote.kdbx {TEMP_DATABASE}" + p.sh.: "sftp user@hostname" ose "scp user@hostname:DatabaseOnRemote.kdbx {TEMP_DATABASE}" + + + Input: + + + + Download input field + + + + Upload + Ngarkim + + + Upload command field + Fushë urdhri ngarkimi + + + e.g.: "sftp user@hostname" or "scp {TEMP_DATABASE} user@hostname:DatabaseOnRemote.kdbx" + e.g.: "sftp user@hostname" ose "scp {TEMP_DATABASE} user@hostname:DatabaseOnRemote.kdbx" + + + Upload input field + + + + Name cannot be empty. + Emri s’mund të jetë i zbrazët. + + + Test + + + + Download command cannot be empty. + Urdhri i shkarkimit s’mund të jetë i zbrazët. + + + Download failed with error: %1 + Shkarkimi dështoi me gabimin: %1 + + + Download finished, but file %1 could not be found. + Shkarkimi përfundoi, por s’u gjeta kartela %1. + + + Download successful. + Shkarkim i suksesshëm + + + Save Remote Settings + + + + You have unsaved changes. Do you want to save them? + Keni ndryshime të paruajtura. Doni të ruhen? + + + e.g.: +get DatabaseOnRemote.kdbx {TEMP_DATABASE} +exit +--- +{TEMP_DATABASE} is used as placeholder to store the database in a temporary location +The command has to exit. In case of `sftp` as last command `exit` has to be sent + + + + + e.g.: +put {TEMP_DATABASE} DatabaseOnRemote.kdbx +exit +--- +{TEMP_DATABASE} is used as placeholder to store the database in a temporary location +The command has to exit. In case of `sftp` as last command `exit` has to be sent + + + + + Timeout: + Mbarime kohe: + + + seconds + sekonda + + DatabaseTabWidget @@ -2192,7 +2527,8 @@ removed from the database. The created database has no key or KDF, refusing to save it. This is definitely a bug, please report it to the developers. - + Baza e të dhënave e krijuar s’ka kyç, apo KDF, po hidhet poshtë ruajtja e saj. +Kjo është përfundimisht një e metë, ju lutemi, njoftojuani zhvilluesve. KeePass 2 Database @@ -2214,25 +2550,9 @@ This is definitely a bug, please report it to the developers. CSV file Kartelë CSV - - Select CSV file - Përzgjidhni kartelë CSV - Merge database - Përzie bazë të dhënash - - - KeePass 1 database - Bazë të dhënash Keepass 1 - - - Open KeePass 1 database - Hap bazë të dhënash Keepass 1 - - - Open OPVault - Hap OPVault + Përzje bazë të dhënash Export database to CSV file @@ -2246,28 +2566,6 @@ This is definitely a bug, please report it to the developers. Writing the HTML file failed. Shkrimi te kartela HTML dështoi. - - Export Confirmation - Ripohim Eksportimi - - - You are about to export your database to an unencrypted file. This will leave your passwords and sensitive information vulnerable! Are you sure you want to continue? - - - - New Database - Bazë e re të Dhënash - - - %1 [New Database] - Database tab name modifier - %1 [Bazë e Re të Dhënash] - - - %1 [Locked] - Database tab name modifier - %1 [E kyçur] - Export database to XML file Eksportoje bazën e të dhënave te kartelë XML @@ -2280,16 +2578,38 @@ This is definitely a bug, please report it to the developers. Writing the XML file failed Shkrimi te kartela XML dështoi + + Export Confirmation + Ripohim Eksportimi + + + You are about to export your database to an unencrypted file. This will leave your passwords and sensitive information vulnerable! Are you sure you want to continue? + Ju ndan një hap nga eksportimi i bazës suaj të të dhënave te një kartelë e pafshehtëzuar. Kjo do t’i lërë të cenueshme fjalëkalimet dhe informacione me spec tuajat! Jeni i sigurt se doni të vazhdohet? + + + %1 [Locked] + Database tab name modifier + %1 [E kyçur] + + + %1 [Temporary] + Database tab name modifier + %1 [E përkohshme] + DatabaseWidget + + Searches and Tags + Kërkime dhe Etiketa + Searching… Po kërkohet… Shared group… - + Grup i përbashkët… Confirm Auto-Type @@ -2297,7 +2617,7 @@ This is definitely a bug, please report it to the developers. Perform Auto-Type into the previously active window? - + Të kryhet Vetë-shtypje te dritarja e mëparshme aktive? Execute command? @@ -2305,7 +2625,7 @@ This is definitely a bug, please report it to the developers. Do you really want to execute the following command?<br><br>%1<br> - + Doni vërtet të ekzekutohet urdhri vijues?<br><br>%1<br> Remember my choice @@ -2321,16 +2641,20 @@ This is definitely a bug, please report it to the developers. Move group to recycle bin? - Të shpihet grupi te koshi i hedhurinave? + Të shpihet grupi te koshi i riciklimeve? Do you really want to move the group "%1" to the recycle bin? - + Doni vërtet të shpihet grupi “%1” te koshi i riciklimeve? Expired entries Zëra të skaduar + + Entries expiring within %1 day(s) + Zëra që skadojnë brenda %1 diteZëra që skadojnë brenda %1 ditësh + No current database. S’ka bazë të tanishme të dhënash. @@ -2355,13 +2679,25 @@ This is definitely a bug, please report it to the developers. No Results S’ka Përfundime + + Save + Ruaje + + + Enter a unique name or overwrite an existing search from the list: + Jepni një emër unik, ose mbishkruani një kërkim ekzistues prej listës: + + + Save Search + Ruaje Kërkimin + Lock Database? Të kyçet Baza e të Dhënave? You are editing an entry. Discard changes and lock anyway? - + Po përpunoni një zë. Të hidhen tej ndryshimet dhe të kyçet, sido qoftë? "%1" was modified. @@ -2383,33 +2719,15 @@ Të ruhen ndryshimet? File has changed Kartela ka ndryshuar - - The database file has changed. Do you want to load the changes? - Kartela e bazës së të dhënave ka ndryshuar. Doni të ngarkohen ndryshimet? - - - Merge Request - Kërkesë Përzierjeje - - - The database file has changed and you have unsaved changes. -Do you want to merge your changes? - Kartela e bazës së të dhënave ka ndryshuar dhe keni ndryshime të paruajtyra. -Doni të përziehen ndryshimet tuaja? - - - Could not open the new database file while attempting to autoreload. -Error: %1 - - Disable safe saves? - + Të çaktivizohen ruajtje të parrezik? KeePassXC has failed to save the database multiple times. This is likely caused by file sync services holding a lock on the save file. Disable safe saves and try again? - + KeePassXC ka dështuar disa herë të ruajë bazën e të dhënave. Kjo ka gjasa të jetë shkaktuar nga shërbime njëkohësimi kartelash që ruajnë një kyçje te kartela që duhet ruajtur. +Të çaktivizohet ruajtje të parrezik dhe të riprovohet? Writing the database failed: %1 @@ -2433,35 +2751,104 @@ Disable safe saves and try again? Empty recycle bin? - Të zbrazet koshi i hedhurinave? + Të zbrazet koshi i riciklimeve? Are you sure you want to permanently delete everything from your recycle bin? - Jeni i sigurt se doni të fshihet përgjithmonë gjithçka prej koshit tuaj të hedhurinave? + Jeni i sigurt se doni të fshihet përgjithmonë gjithçka prej koshit tuaj të riciklimeve? Could not find database file: %1 S’u gjet dot kartelë baze të dhënash: %1 - - Entries expiring within %1 day(s) - Zëra që skadojnë brenda %1 diteZëra që skadojnë brenda %1 ditësh + + New Database + Bazë e re të Dhënash - Searches and Tags - Kërkime dhe Etiketa + %1 [New Database] + Database tab name modifier + %1 [Bazë e Re të Dhënash] - Enter a unique name or overwrite an existing search from the list: - Jepni një emër unik, ose mbishkruani një kërkim ekzistues prej listës: + Remote Sync did not contain any download or upload commands. + Njëkohësimi i Largët s’përmbante ndonjë urdhër shkarkimi ose ngarkimi. - Save - Ruaje + Remote sync '%1' completed successfully! + Njëkohësimi i largët “%1” u plotësua me sukses! - Save Search - Ruaje Kërkimin + Remote sync '%1' failed: %2 + Njëkohësimi i largët “%1” dështoi: %2 + + + Error while saving database %1: %2 + Gabim gjatë ruajtjes së bazës së të dhënave: %1: %2 + + + Downloading... + Po shkarkohet… + + + Uploading... + Po ngarkohet… + + + Syncing... + Po njëkohësohet… + + + Remove passkey from entry + Hiq kodkalim nga zëri + + + Do you want to remove the passkey from this entry? + Doni të hiqet kyçkalimi nga ky zë? + + + The database file "%1" was modified externally + + + + Do you want to load the changes? + + + + Reload database + + + + Reloading database… + + + + Reload canceled + + + + Reload successful + + + + Reload pending user action… + + + + The database file "%1" was modified externally.<br>How would you like to proceed?<br><br>Merge all changes<br>Ignore the changes on disk until save<br>Discard unsaved changes + + + + The database file "%1" was modified externally.<br>How would you like to proceed?<br><br>Merge all changes then save<br>Overwrite the changes on disk<br>Discard unsaved changes + + + + Database file overwritten. + + + + Database file on disk cannot be unlocked with current credentials.<br>Enter new credentials and/or present hardware key to continue. + @@ -2514,10 +2901,6 @@ Disable safe saves and try again? n/a n/a - - (encrypted) - (i fshehtëzuar) - Select private key Përzgjidhni kyç privat @@ -2604,6 +2987,10 @@ Do të donit të ndreqet? Hide Fshihe + + %n hour(s) + %n orë%n orë + %n week(s) %n javë%n javë @@ -2616,9 +3003,9 @@ Do të donit të ndreqet? %n year(s) %n vit%n vjet - - %n hour(s) - %n orë%n orë + + Failed to decrypt SSH key, ensure password is correct. + S’u arrit të shfshehtëzohej kyç, sigurohuni se fjalëkalimi është i saktë. @@ -2708,11 +3095,11 @@ Do të donit të ndreqet? EditEntryWidgetAutoType Enable Auto-Type for this entry - Aktivizo Vetë-Shtypje për këtë zë + Aktivizoni Vetë-Shtypje për këtë zë Inherit default Auto-Type sequence from the group - Trashëgo sekuencë Vetë-Shtypjeje parazgjedhje prej grupit + Trashëgo prej grupit sekuencë parazgjedhje Vetë-Shtypje Use custom Auto-Type sequence: @@ -2738,9 +3125,19 @@ Do të donit të ndreqet? Add new window association Shtoni një përshoqërim të ri dritareje + + + + Add item + + + Remove selected window association - + Hiqe përshoqërimin e përzgjedhur të dritares + + + - + Remove item + - Window title: @@ -2748,15 +3145,15 @@ Do të donit të ndreqet? You can use an asterisk (*) to match everything - + Mund të përdorni një yllth (*) për kërkim përkimesh për gjithçka Set the window association title - + Caktoni titull përshoqërimi dritareje You can use an asterisk to match everything - + Mund të përdorni një yllth për kërkim përkimesh për gjithçka Use a specific sequence for this association: @@ -2764,25 +3161,11 @@ Do të donit të ndreqet? Custom Auto-Type sequence for this window - - - - + - Add item - + - - - - - Remove item - - + Sekuencë vetjake Vetë-Shtypjeje për këtë dritare EditEntryWidgetBrowser - - These settings affect to the entry's behaviour with the browser extension. - - General Të përgjithshme @@ -2795,25 +3178,13 @@ Do të donit të ndreqet? Skip Auto-Submit for this entry Anashkalo Vetë-Parashtrim për këtë zë - - Only send this setting to the browser for HTTP Auth dialogs. If enabled, normal login forms will not show this entry for selection. - - Use this entry only with HTTP Basic Auth - - - - Do not send this setting to the browser for HTTP Auth dialogs. If enabled, HTTP Auth dialogs will not show this entry for selection. - + Këtë zë përdore vetëm me Mirëfilltësim Elementar HTTP Do not use this entry with HTTP Basic Auth - - - - Additional URL's - + Mos e përdor këtë zë me Mirëfilltësim Elementar HTTP Add @@ -2827,6 +3198,22 @@ Do të donit të ndreqet? Edit Përpunojeni + + These settings affect the entry's behaviour with the browser extension. + Këto rregullime prekin sjelljen e zërit me zgjerimin e shfletuesit. + + + Additional URLs + URL-ra shtesë + + + Only send this entry to the browser for HTTP Auth dialogs. If enabled, normal login forms will not show this entry for selection. + Këtë zë dërgoje te shfletuesi vetëm për dialogë Mirëfilltësimesh HTTP. Në u aktivizoftë, formularët normalë të hyrjes s’do ta shfaqin këtë zë për përzgjedhje. + + + Do not send this entry to the browser for HTTP Auth dialogs. If enabled, HTTP Auth dialogs will not show this entry for selection. + Mos e dërgo këtë zë te shfletuesi për dialogë Mirëfilltësimesh HTTP. Në u aktivizoftë, dialogët e Mirëfilltësimeve HTTPf s’do ta shfaqin këtë zë për përzgjedhje. + EditEntryWidgetHistory @@ -2836,7 +3223,7 @@ Do të donit të ndreqet? Show entry at selected history state - + Shfaqe zërin në gjendjen e përzgjedhur të historikut Show @@ -2844,7 +3231,7 @@ Do të donit të ndreqet? Restore entry to selected history state - + Riktheje zërin në gjendjen e përzgjedhur të historikut Restore @@ -2915,7 +3302,7 @@ Do të donit të ndreqet? Toggle expiration - + Shfaq/fshih skadim Tags list @@ -2923,35 +3310,35 @@ Do të donit të ndreqet? &Username: - + &Emër përdoruesi: &Title: - + &Titull: &Password: - + &Fjalëkalim: UR&L: - + UR&L: &Notes: - + Shën&ime: Toggle notes visibility - + Shfaq/fshih shënime T&ags: - + &Etiketa: &Expires: - + &Skadon më: @@ -2962,7 +3349,7 @@ Do të donit të ndreqet? Remove key from agent when database is closed/locked - + Hiqe kyçin nga agjenti, kur mbyllet/kyçet baza e të dhënave Comment @@ -2970,7 +3357,7 @@ Do të donit të ndreqet? Add key to agent when database is opened/unlocked - + Shtoje kyçin te agjenti, kur baza e të dhënave është e hapur/e shkyçur Decrypt @@ -2992,19 +3379,6 @@ Do të donit të ndreqet? Private key Kyç privat - - External file - Kartelë e jashtme - - - Browser for key file - Shfletues për kartelë kyçi - - - Browse… - Button for opening file dialog - Shfletoni… - Attachment Bashkëngjitje @@ -3021,13 +3395,30 @@ Do të donit të ndreqet? Remove from agent Hiqe prej agjenti + + External file + Kartelë e jashtme + + + Browser for key file + Shfletues për kartelë kyçi + + + Browse… + Button for opening file dialog + Shfletoni… + + + Generate + Prodhoje + Select attachment file Përzgjidhni kartelë bashkëngjitje Require user confirmation when this key is used - + Kërko doemos ripohim nga përdoruesi, kur përdoret ky kyç n/a @@ -3035,16 +3426,20 @@ Do të donit të ndreqet? Remove key from agent after - + Hiqe kyçin nga agjenti pas Remove key from agent after specified seconds - + Hiqe kyçin nga agjenti pas sekondave të specifikuara seconds sekonda + + Clear agent + + EditGroupWidget @@ -3056,10 +3451,6 @@ Do të donit të ndreqet? Icon Ikonë - - Browser Integration - Integrim Shfletuesi - Properties Veti @@ -3076,6 +3467,10 @@ Do të donit të ndreqet? Group has unsaved changes Grupi ka ndryshime të paruajtura + + Browser Integration + Integrim Shfletuesi + Enable Aktivizoje @@ -3093,11 +3488,11 @@ Do të donit të ndreqet? EditGroupWidgetBrowser These settings affect to the group's behaviour with the browser extension. - + Këto rregullime prekin sjelljen e grupit me zgjerimin e shfletuesit. Hide entries from browser extension: - + Fshihi zërat nga zgjerimi i shfletuesit: Hide entries from browser extension toggle for this and sub groups @@ -3105,7 +3500,7 @@ Do të donit të ndreqet? Skip Auto-Submit for entries: - + Anashkalo Vetëparashtrim për zërat: Skip Auto-Submit toggle for this and sub groups @@ -3113,7 +3508,7 @@ Do të donit të ndreqet? Use entries only with HTTP Basic Auth: - + Përdori zërat vetëm me Mirëfilltësim Elementar HTTP: Only HTTP Auth toggle for this and sub groups @@ -3121,7 +3516,7 @@ Do të donit të ndreqet? Do not use entries with HTTP Basic Auth: - + Mos përdor zëra me Mirëfilltësim Elementar HTTP: Do not use HTTP Auth toggle for this and sub groups @@ -3129,18 +3524,26 @@ Do të donit të ndreqet? Omit WWW subdomain from matching: - + Lër jashtë kërkimit për përkim nënpërkatësinë WWW: Omit WWW subdomain from matching toggle for this and sub groups + + Restrict matching to given browser key: + + + + Restrict matching to given browser key toggle for this and sub groups + + EditGroupWidgetKeeShare Sharing mode field - + Fushë mënyre ndarjeje me të tjerë Password field @@ -3160,11 +3563,11 @@ Do të donit të ndreqet? Path to share file field - + Fushë shtegu për të ndarë kartelë me të tjerë Browse for share file - + Shfletoni për kartelë për ndarje Browse… @@ -3197,40 +3600,41 @@ Do të donit të ndreqet? Your KeePassXC version does not support sharing this container type. Supported extensions are: %1. - + Versioni juaj i KeePassXC-së nuk mbulon ndarje të këtij lloji kontejneri. +Zgjatimet e mbuluara janë: %1. %1 is already being exported by this database. - + %1 po eksportohet tashmë nga kjo bazë të dhënash. %1 is already being imported by this database. - + %1 po importohet tashmë nga kjo bazë të dhënash. %1 is being imported and exported by different groups in this database. - + %1 po importohet dhe eksportohet nga grupe të ndryshëm në këtë bazë të dhënash. KeeShare is currently disabled. You can enable import/export in the application settings. KeeShare is a proper noun - + KeeShare është aktualisht i çaktivizuar. Mund të aktivizoni importim/eksportim që nga rregullime aplikacioni. Database export is currently disabled by application settings. - + Eksportimi i bazës së të dhënave është aktualisht i çaktivizuar që nga rregullime aplikacioni. Database import is currently disabled by application settings. - + Importimi i bazës së të dhënave është aktualisht i çaktivizuar që nga rregullime aplikacioni. KeeShare container - + Kontejner KeeShare KeeShare signed container - + Kontejner KeeShare i nënshkruar Select import source @@ -3253,7 +3657,7 @@ Supported extensions are: %1. Toggle expiration - + Shfaq/fshih skadim Expires: @@ -3269,7 +3673,7 @@ Supported extensions are: %1. Use default Auto-Type sequence of parent group - + Përdor sekuencë Vetë-Shtypjeje parazgjedhje të grupit mëmë Auto-Type: @@ -3366,10 +3770,6 @@ Supported extensions are: %1. Unable to fetch favicon. S’arrihet të sillet favikonë. - - You can enable the DuckDuckGo website icon service under Tools -> Settings -> Security - - Existing icon selected. U përzgjodh ikonë ekzistuese. @@ -3388,7 +3788,7 @@ Supported extensions are: %1. Successfully loaded %1 of %n icon(s) - + U ngarkua me sukses %1 nga %n ikonëU ngarkua me sukses %1 nga %n ikona No icons were loaded @@ -3396,22 +3796,26 @@ Supported extensions are: %1. %n icon(s) already exist in the database - + Te baza e të dhënave ekziston tashmë %n ikonëTe baza e të dhënave ekzistojnë tashmë %n ikona The following icon(s) failed: Ikona vijuese dështoi:Ikonat vijuese dështuan: + + You can enable the DuckDuckGo website icon service under Application Settings -> Security + Mund të aktivizoni shërbim ikonash sajti DuckDuckGo që nga Rregullime Aplikacioni -> Siguri + EditWidgetProperties Created: - Krijuar më + Krijuar më: Datetime created - + Datë dhe kohë kur u krijua Modified: @@ -3419,15 +3823,15 @@ Supported extensions are: %1. Datetime modified - + Datë dhe kohë kur u ndryshua Accessed: - + Përdorur më: Datetime accessed - + Datë dhe kohë kur u përdor Uuid: @@ -3447,7 +3851,7 @@ Supported extensions are: %1. Remove selected plugin data - + Hiq të dhëna shtojce të përzgjedhur Remove @@ -3455,12 +3859,13 @@ Supported extensions are: %1. Delete plugin data? - + Të hiqen të dhëna shtojce? Do you really want to delete the selected plugin data? This may cause the affected plugins to malfunction. - + Doni vërtet të fshihen të dhënat e shtojcës së përzgjedhur? +Kjo mund të bëjë të punojnë keq shtojcat e prekura. Key @@ -3475,7 +3880,25 @@ This may cause the affected plugins to malfunction. Entry %1 - Clone - + %1 - Klonoje + + + Passkey + Kyçkalim + + + Invalid conversion type: %1 + Lloj i pavlefshëm shndërrimi: %1 + + + Invalid conversion syntax: %1 + Sintaksë e pavlefshme shndërrimi: %1 + + + Invalid regular expression syntax %1 +%2 + Sintaksë e pavlefshme shprehjeje të rregullt: %1 +%2 @@ -3485,6 +3908,21 @@ This may cause the affected plugins to malfunction. S’hapet dot kartela “%1” + + EntryAttachmentsDialog + + Form + Formular + + + File name + + + + File contents... + + + EntryAttachmentsModel @@ -3522,14 +3960,6 @@ This may cause the affected plugins to malfunction. Remove Hiqe - - Rename selected attachment - Riemërtojeni bashkëngjitjen e përzgjedhur - - - Rename - Riemërtojeni - Open selected attachment Hape bashkëngjitjen e përzgjedhur @@ -3556,7 +3986,7 @@ This may cause the affected plugins to malfunction. Are you sure you want to remove %n attachment(s)? - Jeni i sigurt se doni të hiqet %n bashkëngjitje?Jeni i sigurt se doni të hiqet %n bashkëngjitje? + Jeni i sigurt se doni të hiqet %n bashkëngjitje?Jeni i sigurt se doni të hiqen %n bashkëngjitje? Save attachments @@ -3570,7 +4000,7 @@ This may cause the affected plugins to malfunction. Are you sure you want to overwrite the existing file "%1" with the attachment? - + Jeni i sigurt se doni të mbishkruhet kartela ekzistuese “%1” me bashkëngjitjen? Confirm overwrite @@ -3605,11 +4035,6 @@ This may cause the affected plugins to malfunction. Confirm Overwrite Attachment Ripohoni Mbishkrim Bashkëngjitjeje - - Attachment "%1" already exists. -Would you like to overwrite the existing attachment? - - Confirm Attachment Ripohoni Bashkëngjitje @@ -3619,7 +4044,10 @@ Would you like to overwrite the existing attachment? Your database may get very large and reduce performance. Are you sure to add this file? - + %1 është një kartelë e madhe (%2 MB). +Baza juaj e të dhënave mund të bëhet shumë e madhe dhe të bjerë funksionimi. + +Jeni i sigurt se doni të shtohet kjo kartelë? Attachment modified @@ -3628,15 +4056,35 @@ Are you sure to add this file? The attachment '%1' was modified. Do you want to save the changes to your database? - + Bashkëngjitja “%1” u ndryshua. +Doni të ruhen ndryshimet te baza juaj e të dhënave? Saving attachment failed - + Dështoi ruajtja e bashkëngjitjes Saving updated attachment failed. Error: %1 + Dështoi ruajtja e bashkëngjitjes së përditësuar. +Gabim: %1 + + + Attachment "%1" already exists. +Would you like to overwrite the existing attachment? + Ka tashmë një bashkëngjitje “%1”. +Doni të mbishkruhet bashkëngjitja ekzistuese? + + + New + + + + Preview + Paraparje + + + Failed to preview an attachment: Attachment not found @@ -3651,7 +4099,7 @@ Error: %1 EntryHistoryModel Current (%1) - + I tanishmi (%1) Last modified @@ -3731,7 +4179,7 @@ Error: %1 Ref: Reference abbreviation - + Ref: Never @@ -3775,7 +4223,7 @@ Error: %1 Accessed - + Përdorur më Attachments @@ -3815,7 +4263,7 @@ Error: %1 Last access date - + Data e përdorimit të fundit Attached files @@ -3833,12 +4281,20 @@ Error: %1 Has TOTP Ka TOTP + + Background Color + Ngjyrë Sfondi + + + Group Path + + EntryPreviewWidget Display current TOTP value - + Shfaq vlerën e tanishme TOTP Close @@ -3853,8 +4309,8 @@ Error: %1 Fjalëkalim - Notes - Shënime + URL + URL Expiration @@ -3873,8 +4329,8 @@ Error: %1 Emër përdoruesi - URL - URL + Notes + Shënime Advanced @@ -3890,7 +4346,7 @@ Error: %1 Autotype - + Vetë-shtype Default Sequence @@ -3906,11 +4362,11 @@ Error: %1 Searching - + Po kërkohet Share - + Ndaje me të tjerë Search @@ -3924,6 +4380,10 @@ Error: %1 Never Kurrë + + Double click to copy value + Që t’i kopjohet vlera, dyklikojeni + Enabled E aktivizuar @@ -3932,35 +4392,31 @@ Error: %1 Disabled E çaktivizuar - - Double click to copy value - Që t’i kopjohet vlera, dyklikojeni - Double click to copy to clipboard - + Që të kopjohet, dyklikojeni EntryURLModel Invalid URL - URL e Pavlefshme + URL e pavlefshme Duplicate URL - + URL e përsëdytur EntryView Fit to window - + Sa ta nxërë dritarja Fit to contents - + Sa ta nxërë lënda Reset to defaults @@ -3968,7 +4424,7 @@ Error: %1 + %1 entry(s)... - + + %1 zë…+ %1 zëra… @@ -3985,7 +4441,9 @@ Error: %1 You are about to export your database to an unencrypted file. This will leave your passwords and sensitive information vulnerable! - + Ju ndan një hap nga eksportimi i bazës suaj të të dhënave si një kartelë e pafshehtëzuar. +Kjo do t’i lërë të cenueshme fjalëkalimet tuaja dhe informacione me spec! + database order @@ -4016,61 +4474,61 @@ This will leave your passwords and sensitive information vulnerable! FdoSecrets::DBusMgr Failed to deliver message - + S’u arrit të dërgohej mesazhe Failed to send reply on DBus - + S’u arrit të dërgohej përgjigje në DBUS Unknown Unknown PID - + I panjohur Unknown Unknown executable path - + I panjohur <i>PID: %1, Executable: %2</i> <i>PID: 1234, Executable: /path/to/exe</i> - + <i>PID: %1, I ekzekutueshëm: %2</i> Another secret service is running (%1).<br/>Please stop/remove it before re-enabling the Secret Service Integration. - + Po xhiron një tjetër shërbim i fshehtë (%1).<br/>Ju lutemi, ndaleni/hiqeni, para se të riaktivizohet Integrimi i Shërbimit të Fshehtë. Failed to register DBus service at %1.<br/> - + S’u arrit të regjistrohej shërbim DBus në %1.<br/> Failed to register service on DBus at path '%1' - + S’u arrit të regjistrohej shërbim DBus në shtegun '%1' Failed to register database on DBus under the name '%1' - + S’u arrit të regjistrohej bazë të dhënash te DBus nën emrin '%1' Failed to register session on DBus at path '%1' - + S’u arrit të regjistrohej sesion te DBus në shtegun '%1' Failed to register item on DBus at path '%1' - + S’u arrit të regjistrohej objekt te DBus në shtegun '%1' Failed to register prompt object on DBus at path '%1' - + S’u arrit të regjistrohej objekt prompt te DBus në shtegun '%1' FdoSecrets::Item Entry "%1" from database "%2" was used by %3 - + Nga %3 u përdor zëri “%1” pre bazës së të dhënave “%2” @@ -4078,14 +4536,14 @@ This will leave your passwords and sensitive information vulnerable! %n Entry(s) was used by %1 %1 is the name of an application - + Nga %1 qe përdorur %n zëNga %1 qenë përdorur %n zëra FdoSecrets::SettingsClientModel Unknown - + I panjohur Non-existing/inaccessible executable path. Please double-check the client is legit. @@ -4096,7 +4554,7 @@ This will leave your passwords and sensitive information vulnerable! FdoSecrets::SettingsDatabaseModel Unlock to show - + Që të shfaqet, shkyçeni None @@ -4114,7 +4572,7 @@ This will leave your passwords and sensitive information vulnerable! FdoSecretsPlugin <b>Fdo Secret Service:</b> %1 - + <b>Shërbim të Fshehtash Fdo:</b> %1 @@ -4126,21 +4584,21 @@ This will leave your passwords and sensitive information vulnerable! %1 - Clone - + %1 - Klonoje HibpDownloader Online password validation failed - + Dështoi vlerësimi në internet i fjalëkalimit IconDownloaderDialog Download Favicons - + Shkarko Favikona Cancel @@ -4149,7 +4607,8 @@ This will leave your passwords and sensitive information vulnerable! Having trouble downloading icons? You can enable the DuckDuckGo website icon service in the security section of the application settings. - + Keni probleme me shkarkim ikonash? +Mund të aktivizoni shërbimin e ikonave të sajteve nga DuckDuckGo, te pjesa e sigurisë në rregullimet e aplikacionit. Close @@ -4165,7 +4624,7 @@ You can enable the DuckDuckGo website icon service in the security section of th Please wait, processing entry list… - + Ju lutemi, prisni, po përpunohet listë zërash… Downloading… @@ -4188,6 +4647,193 @@ You can enable the DuckDuckGo website icon service in the security section of th Po shkarkohen favikona (%1/%2)… + + ImportWizard + + Import Wizard + Ndihmës Importimesh + + + + ImportWizardPageReview + + WizardPage + Faqe Ndihmësi + + + Entry count: %1 + Numër zërash: %1 + + + Group + Grup + + + Title + Titull + + + Username + Emër përdoruesi + + + Password + Fjalëkalim + + + Url + URL + + + Could not load key file. + S’u ngarkua dot kartelë kyç. + + + Could not open remote database. Password or key file may be incorrect. + S’u hap dot bazë e largët të dhënash. Mund të jenë të pasaktë fjalëkalimi ose kartela kyç. + + + + ImportWizardPageSelect + + Form + Formular + + + Import File Selection + Përzgjedhje Kartele Importimi + + + Password: + Fjalëkalim: + + + Key File: + Kartelë Kyçi: + + + Browse… + Shfletoni… + + + Import Into: + Importoje Te: + + + New Database + Bazë e re të Dhënash + + + No unlocked databases available + S’ka baza të dhënash të shkyçura + + + Existing Database: + Bazë Ekzistuese të Dhënash: + + + Import File: + Importo Kartelë: + + + Comma Separated Values (.csv) + Vlera Ndarë Me Presje (.csv) + + + 1Password Export (.1pux) + Eksportim 1Password (.1pux) + + + 1Password Vault (.opvault) + Kasafortë 1Password (.opvault) + + + Bitwarden (.json) + Bitwarden (.json) + + + KeePass 1 Database (.kdb) + Bazë të dhënash KeePass 1 (.kdb) + + + Open OPVault + Hap OPVault + + + Select import file + Përzgjidhni kartelë importimi + + + All files + Krejt kartelat + + + Key files + Kartela kyçesh + + + Select key file + Përzgjidhni kartelë kyçi + + + Comma Separated Values + Vlera Ndarë Me Presje + + + 1Password Export + Eksportim 1Password + + + Bitwarden JSON Export + Eksportim Bitwarden JSON + + + 1Password Vault + Kasafortë 1Password + + + KeePass1 Database + Bazë të Dhënash Keepass1 + + + Proton Pass (.json) + + + + Proton Pass JSON Export + + + + Temporary Database + Bazë e përkohshme të Dhënash + + + Command: + Urdhër: + + + e.g.: "sftp user@hostname" or "scp user@hostname:DatabaseOnRemote.kdbx {TEMP_DATABASE}" + p.sh.: "sftp user@hostname" ose "scp user@hostname:DatabaseOnRemote.kdbx {TEMP_DATABASE}" + + + Input: + + + + e.g.: +get DatabaseOnRemote.kdbx {TEMP_DATABASE} +exit +--- +{TEMP_DATABASE} is used as placeholder to store the database in a temporary location +The command has to exit. In case of `sftp` as last commend `exit` has to be sent + + + + + Remote Database (.kdbx) + Bazë të Dhënash e Largët (.kdbx) + + KMessageWidget @@ -4196,43 +4842,44 @@ You can enable the DuckDuckGo website icon service in the security section of th Close message - + Mbylle mesazhin Kdbx3Reader Missing database headers - + Mungojnë krye baze të dhënash Unable to calculate database key - + S’arrihet të llogaritet kyç baze të dhënash Unable to issue challenge-response: %1 - + S’arrihet të emetohet pyetje-përgjigje: %1 Invalid credentials were provided, please try again. If this reoccurs, then your database file may be corrupt. - + U dhanë kredenciale të pavlefshme, ju lutemi, riprovoni. +Nëse kjo ndodh sërish, ahere baza juaj e të dhënave mund të jetë e dëmtuar. Header doesn't match hash - + Kryet s’përputhen me hashin Invalid header id size - + Madhësi e pavlefshme ID-je kryesh Invalid header field length: field %1 - + Gjatësi e pavlefshme fushe kryesh: fushë %1 Invalid header data length: field %1, %2 expected, %3 found - + Gjatësi e pavlefshme të dhënash kryesh: fushë %1, pritej %2, u gjet %3 @@ -4240,83 +4887,84 @@ If this reoccurs, then your database file may be corrupt. Invalid symmetric cipher IV size. IV = Initialization Vector for symmetric cipher - + Madhësi e pavlefshme Vektori simetrik gatitjeje shifre. Unable to issue challenge-response: %1 - + S’arrihet të emetohet pyetje-përgjigje: %1 Unable to calculate database key - + S’arrihet të llogaritet kyç baze të dhënash Kdbx4Reader missing database headers - + mungojnë krye baze të dhënash Unable to calculate database key: %1 - + S’arrihet të llogaritet kyç baze të dhënash: %1 Invalid header checksum size - + Madhësi e pavlefshme checksum-i kryesh Header SHA256 mismatch - + Mospërputhje kryesh SHA256 Invalid credentials were provided, please try again. If this reoccurs, then your database file may be corrupt. - + U dhanë kredenciale të pavlefshme, ju lutemi, riprovoni. +Nëse kjo ndodh sërish, ahere baza juaj e të dhënave mund të jetë e dëmtuar. (HMAC mismatch) - + (Mospërputhje HMAC) Unknown cipher - + Shifër e panjohur Invalid header id size - + Madhësi e pavlefshme ID-je kryesh Invalid header field length: field %1 - + Gjatësi e pavlefshme fushe kryesh: fushë %1 Invalid header data length: field %1, %2 expected, %3 found - + Gjatësi e pavlefshme të dhënash kryesh: fushë %1, pritej %2, u gjet %3 Failed to open buffer for KDF parameters in header - + S’u arrit të hapet “buffer” për parametra KDFte kryet Unsupported key derivation function (KDF) or invalid parameters - + Funksion i pambuluar derivimi kyçesh (KDF), ose parametra të pavlefshëm Legacy header fields found in KDBX4 file. - + U gjetën fusha kryesh të dikurshme në kartelë KDBX4. Invalid inner header id size - + Madhësi ID-je kryesh të brendshme Invalid inner header field length: field %1 - + Gjatësi e pavlefshme fushe kryesh të brendshme: fusha %1 Invalid inner header data length: field %1, %2 expected, %3 found - + Gjatësi e pavlefshme fushe kryesh të brendshme: fusha %1, pritej %2, u gjet %3 Invalid inner header binary size @@ -4387,16 +5035,16 @@ If this reoccurs, then your database file may be corrupt. Kdbx4Writer Invalid symmetric cipher algorithm. - + Algoritëm i pavlefshëm shifre simetrike. Invalid symmetric cipher IV size. IV = Initialization Vector for symmetric cipher - + Madhësi e pavlefshme Vektori Gatitjeje shifre simetrike. Unable to calculate database key: %1 - + S’arrihet të llogaritet kyç baze të dhënash: %1 Failed to serialize KDF parameters variant map @@ -4408,15 +5056,15 @@ If this reoccurs, then your database file may be corrupt. KdbxReader Invalid cipher uuid length: %1 (length=%2) - + Gjatësi e pavlefshme UUID-je shifre: %1 (gjatësi=%2) Unable to parse UUID: %1 - + S’arrihet të analizohet UUID: %1 Unsupported cipher - + Shifër e pambuluar Invalid compression flags length @@ -4424,7 +5072,7 @@ If this reoccurs, then your database file may be corrupt. Unsupported compression algorithm - + Algoritëm i pambuluar ngjeshjesh Invalid master seed size @@ -4436,11 +5084,11 @@ If this reoccurs, then your database file may be corrupt. Invalid transform rounds size - + Madhësi e pavlefshme raundesh shndërrimi Invalid start bytes size - + Madhësi e pavlefshme bajtesh fillimi Invalid random stream id size @@ -4452,14 +5100,17 @@ If this reoccurs, then your database file may be corrupt. Failed to read database file. - + S’u arrit të lexohej kartelë baze të dhënash. The selected file is an old KeePass 1 database (.kdb). You can import it by clicking on Database > 'Import KeePass 1 database…'. This is a one-way migration. You won't be able to open the imported database with the old KeePassX 0.4 version. - + Kartela e përzgjedhur është një bazë e vjetër të dhënash KeePass 1 (.kdb). + +Mund ta importoni duke klikuar te Bazë të dhënash > “Importoni bazë të dhënash KeePass 1…”. +Ky është një migrim me një kah. S’do të jeni në gjendje të hapni bazën e importuar të të dhënave me versionin e vjetër KeePassX 0.4. Not a KeePass database. @@ -4467,32 +5118,34 @@ This is a one-way migration. You won't be able to open the imported databas Unsupported KeePass 2 database version. - + Version i pambuluar baze të dhënash KeePass 2. KdbxXmlReader XML parsing failure: %1 - + Dështim analizimi XML-je: %1 No root group - + S’ka grup rrënjë XML error: %1 Line %2, column %3 - + Gabim XML: +%1 +Rreshti %2, shtylla %3 Missing icon uuid or data - + Mungon UUID ose të dhëna ikone Missing custom data key or value - + Mungon kyç, ose vlerë të dhënash vetjake Multiple group elements @@ -4504,19 +5157,19 @@ Line %2, column %3 Invalid group icon number - + Numër i pavlefshëm ikonash grupi Invalid EnableAutoType value - + Vlerë EnableAutoType e pavlefshme Invalid EnableSearching value - + Vlerë EnableSearching e pavlefshme No group uuid found - + S’u gjet grup UUID Null DeleteObject uuid @@ -4524,7 +5177,7 @@ Line %2, column %3 Missing DeletedObject uuid or time - + Mungon UUID ose kohë për DeletedObject Null entry uuid @@ -4532,23 +5185,23 @@ Line %2, column %3 Invalid entry icon number - + Numër i pavlefshëm ikone zëri History element in history entry - + Element historiku te zë historiku No entry uuid found - + S’u gjet UUID zëri History element with different uuid - + Element historiku me UUDI të ndryshme Duplicate custom attribute found - + U gjet atribut vetjak i përsëdytur Entry string key or value missing @@ -4560,77 +5213,66 @@ Line %2, column %3 Auto-type association window or sequence missing - + Mungon dritare ose sekuencë përshoqërimi Vetë-shtypjeje Invalid bool value - + Vlerë buelane e pavlefshme Invalid date time value - + Vlerë e pavlefshme date kohe Invalid color value - + Vlerë e pavlefshme ngjyre Invalid color rgb part - + Pjesë e pavlefshme RGB ngjyre Invalid number value - + Vlerë e pavlefshme numri Invalid uuid value - + Vlerë UUID e pavlefshme Unable to decompress binary Translator meant is a binary data inside an entry - + S’arrihet të çngjeshet dyor KeeAgentSettings Invalid KeeAgent settings file structure. - + Strukturë e pavlefshme kartele rregullimesh KeeAgent. Private key is an attachment but no attachments provided. - + Kyçi privat është një bashkëngjitje, por bashkëngjitje s’u dhanë. Private key is empty - + Kyçi privat është i zbrazët File too large to be a private key - + Kartelë shumë e madhe për të qenë një kyç privat Failed to open private key - - - - - KeePass1OpenWidget - - Import KeePass1 Database - Importo Bazë të Dhënash Keepass 1 - - - Unable to open the database. - S’arrihet të hapet baza e të dhënave. + S’u arrit të hapej kyç privat KeePass1Reader Unable to read keyfile. - S’arrihet të lexohet kartelë kyçesh. + S’arrihet të lexohet kartelë kyç. Not a KeePass database. @@ -4638,28 +5280,28 @@ Line %2, column %3 Unsupported encryption algorithm. - + Algoritëm i pambuluar fshehtëzimesh. Unsupported KeePass database version. - + Version i pambuluar baze të dhënash KeePass. Unable to read encryption IV IV = Initialization Vector for symmetric cipher - + S’arrihet të lexohet VG fshehtëzimi Invalid number of groups - + Numër i pavlefshëm grupesh Invalid number of entries - + Numër i pavlefshëm zërash Invalid content hash size - + Madhësi e pavlefshme hashi lënde Invalid transform seed size @@ -4667,7 +5309,7 @@ Line %2, column %3 Invalid number of transform rounds - + Numër i pavlefshëm raundesh shndërrimi Unable to construct group tree @@ -4675,11 +5317,11 @@ Line %2, column %3 Root - + Rrënjë Unable to calculate database key - + S’arrihet të llogaritet kyç baze të dhënash unable to seek to content position @@ -4688,19 +5330,20 @@ Line %2, column %3 Invalid credentials were provided, please try again. If this reoccurs, then your database file may be corrupt. - + U dhanë kredenciale të pavlefshme, ju lutemi, riprovoni. +Nëse kjo ndodh sërish, ahere baza juaj e të dhënave mund të jetë e dëmtuar. Key transformation failed - + Shndërrimi i kyçit dështoi Invalid group field type number - + Numër i pavlefshëm lloji fushe grupi Invalid group field size - + Madhësi fushe grupi e pavlefshme Read group field data doesn't match size @@ -4708,47 +5351,47 @@ If this reoccurs, then your database file may be corrupt. Incorrect group id field size - + Madhësi e pasaktë fushe ID-je grupi Incorrect group creation time field size - + Madhësi e pasaktë fushe kohe krijimi grupi Incorrect group modification time field size - + Madhësi e pasaktë fushe kohe ndryshimi grupi Incorrect group access time field size - + Madhësi e pasaktë fushe kohe përdorimi grupi Incorrect group expiry time field size - + Madhësi e pasaktë fushe kohe skadimi grupi Incorrect group icon field size - + Madhësi e pasaktë fushe ikone grupi Incorrect group level field size - + Madhësi e pasaktë fushe niveli grupi Invalid group field type - + Lloj i pavlefshëm fushe grupi Missing group id or level - + Mungon ID ose nivel grupi Missing entry field type number - + Mungon numër lloji fushe zëri Invalid entry field size - + Madhësi e pavlefshme fushe zëri Read entry field data doesn't match size @@ -4756,31 +5399,31 @@ If this reoccurs, then your database file may be corrupt. Invalid entry UUID field size - + Madhësi e pavlefshme fushe UUID zëri Invalid entry group id field size - + Madhësi e pavlefshme fushe ID-je grupi zëri Invalid entry icon field size - + Madhësi e pavlefshme fushe ikone zëri Invalid entry creation time field size - + Madhësi e pavlefshme fushe kohe krijimi zëri Invalid entry modification time field size - + Madhësi e pavlefshme fushe kohe ndryshimi zëri Invalid entry expiry time field size - + Madhësi e pavlefshme fushe kohe skadimi zëri Invalid entry field type - + Madhësi e pavlefshme fushe zëri @@ -4799,19 +5442,19 @@ If this reoccurs, then your database file may be corrupt. Exported to %1 - + Eksportuar te %1 Synchronized with %1 - + Njëkohësuar me %1 Import is disabled in settings - + Importimi është i çaktivizuar te rregullimet Export is disabled in settings - + Eksportimi është i çaktivizuar te rregullimet Inactive share @@ -4819,15 +5462,15 @@ If this reoccurs, then your database file may be corrupt. Imported from - + Importuar nga Exported to - + Eksportuar te Synchronized with - + Njëkohësuar me @@ -4853,7 +5496,7 @@ If this reoccurs, then your database file may be corrupt. KeyFileEditWidget Generate a new key file - + Prodhoni një kartelë të re kyçi Generate @@ -4861,11 +5504,11 @@ If this reoccurs, then your database file may be corrupt. Generate a new key file or choose an existing one to protect your database. - + Prodhoni një kartelë të re kyçi, ose zgjidhni nëj ekzistuese, që të mbroni bazën tuaj të të dhënave. Note: Do NOT use a file that may change as that will prevent you from unlocking your database. - + Shënim: MOS përdorni një kartelë që mund të ndryshojë, ngaqë kjo do t’ju pengojë të shkyçni bazën tuaj të të dhënave. Browse for key file @@ -4881,12 +5524,13 @@ If this reoccurs, then your database file may be corrupt. You selected a key file in an old format which KeePassXC<br>may stop supporting in the future.<br><br>Please consider generating a new key file instead. - + Përzgjodhët një kartelë kyçi në një format të vjetër. të cilin KeePassXC-ja<br>mund të reshtë së mbuluari në të ardhmen.<br><br>Ju lutemi, në vend të kësaj, shihni mundësinë e prodhimit të një kartele të re. Error loading the key file '%1' Message: %2 - + Gabim në ngarkimin e kartelës së kyçit “%1” +Mesazh: %2 Key File @@ -4906,11 +5550,11 @@ Message: %2 Key File set, click to change or remove - + Kartela e Kyçit u ujdis, klikoni që ta ndryshoni, ose hiqni <p>You can add a key file containing random bytes for additional security.</p><p>You must keep it secret and never lose it or you will be locked out.</p> - + <p>Mund të shtoni një kartelë kyçi që përmban bajte kuturu, për më tepër siguri.</p><p>Duhet ta mbani të fshehtë dhe të mos e humbni kurrë, përndryshe do të kyçeni jashtë.</p> Key files @@ -4930,7 +5574,8 @@ Message: %2 Unable to create key file: %1 - + S’arrihet të krijohet kartelë kyçi: +%1 Select a key file @@ -4942,7 +5587,7 @@ Message: %2 You cannot use the current database as its own keyfile. Please choose a different file or generate a new key file. - + S’mund të përdorni bazën e tanishme të të dhënave si kartelë kyçi për veten. Ju lutemi, zgjidhni një kartelë tjetër, ose prodhoni një kartelë të re kyçi. Suspicious Key File @@ -4951,7 +5596,8 @@ Message: %2 The chosen key file looks like a password database file. A key file must be a static file that never changes or you will lose access to your database forever. Are you sure you want to continue with this file? - + Kartela e zgjedhur e kyçit duket si një kartelë fjalëkalimi baze të dhënash. Një kartelë kyçi duhet të jetë një kartelë statike që nuk ndryshon kurrë, ose përndryshe do të humbni përgjithmonë hyrjen te baza juaj e të dhënave. +Jeni i sigurt se doni të vazhdohet me këtë kartelë? @@ -4973,36 +5619,36 @@ Are you sure you want to continue with this file? MainWindow &Database - + &Bazë të dhënash &Recent Databases - - - - &Import - + Baza të dhënash Së &Fundi &Export - + &Eksporto &Help - + &Ndihmë &Entries - + &Zëra Copy Att&ribute - + Kopjo Atri&but TOTP TOTP + + Tags + Etiketa + &Groups &Grupe @@ -5021,7 +5667,7 @@ Are you sure you want to continue with this file? &Quit - + &Mbylle &About @@ -5029,227 +5675,163 @@ Are you sure you want to continue with this file? &Check for Updates - + &Kontrollo për Përditësime &Open Database… - + &Hapni Bazë të Dhënash… &Save Database - + &Ruaje Bazën e të Dhënave &Close Database - + Mby&lle Bazën e të Dhënave &New Database… - - - - Create a new database - + Bazë e R&e të Dhënash… &Merge From Database… - - - - Merge from another KDBX database - + &Përzieni Prej Baze të Dhënash… &New Entry… - - - - Add a new entry - Shtoni zë të ri + Zë i &Ri… &Edit Entry… - - - - View or edit entry - Shihni ose përpunoni zë + Përp&unoni Zë… &Delete Entry… - + &Fshini Zë… &New Group… - - - - Add a new group - + &Grup i Ri… &Edit Group… - + &Përpunoni Grup… &Delete Group… - + &Fshini Grup… Download All &Favicons… - + Shkarkoni Krejt F&avikonat… Sort &A-Z - + Renditi sipas &A-Z Sort &Z-A - + Renditi sipas &Z-A Sa&ve Database As… - + R&uajeni Bazën e të Dhënave Si… Database &Security… - + &Siguri Baze të Dhënash… Database &Reports… - - - - Statistics, health check, etc. - + &Raporte Baze të Dhënash… &Database Settings… - - - - Database settings - Rregullime baze të dhënash + Rregullime &Baze të Dhënash… &Clone Entry… - + &Klononi Zë… Move u&p - - - - Move entry one step up - + &Ngjite sipër Move do&wn - - - - Move entry one step down - + Zbrite &poshtë Copy &Username - - - - Copy username to clipboard - + &Kopjo Emër Përdoruesi Copy &Password - - - - Copy password to clipboard - Kopjoje fjalëkalimin në të papastër + Kopjo &Fjalëkalimin &Settings - + &Rregullime &Password Generator - + Prodhues &Fjalëkalimesh Perform &Auto-Type - + kryej &Vetë-Shtypje Download &Favicon - + Shkarko F&avikonë Open &URL - + Hape &URL-në &Lock Database - + &Kyçe Bazën e të Dhënave Lock &All Databases - + Kyçi &Krejt Bazat e të Dhënave &Title - + &Titull - Copy title to clipboard - - - - Copy URL to clipboard - + Copy &URL + Kopjoji &URL-në &Notes - - - - Copy notes to clipboard - + Shëni&me &CSV File… - + Kartelë &CSV… &HTML File… - + Kartelë &HTML… KeePass 1 Database… - - - - Import a KeePass 1 database - + Bazë të Dhënash Keepass 1… 1Password Vault… - - - - Import a 1Password Vault - + Kasafortë 1Password… CSV File… - - - - Import a CSV file - + Kartelë CSV… Show TOTP - + Shfaq TOTP Show QR Code @@ -5263,9 +5845,13 @@ Are you sure you want to continue with this file? Copy &TOTP Kopjo &TOTP + + Copy Password and TOTP + Kopjo Fjalëkalim dhe TOTP + E&mpty recycle bin - &Zbraz koshin e hedhurinave + &Zbraz koshin e riciklimeve &Donate @@ -5287,10 +5873,6 @@ Are you sure you want to continue with this file? &Online Help Ndihmë Në &Internet - - Go to online documentation - Kalo te dokumentimi në internet - &User Guide &Udhërrëfyes Përdoruesi @@ -5321,7 +5903,7 @@ Are you sure you want to continue with this file? Automatic - + Automatike Light @@ -5333,7 +5915,11 @@ Are you sure you want to continue with this file? Classic (Platform-native) - + Klasike(E brendshme e platformës) + + + Show Menubar + Shfaq shtyllë menush Show Toolbar @@ -5359,6 +5945,10 @@ Are you sure you want to continue with this file? Clone Group... Klononi Grup… + + &XML File… + Kartelë &XML… + Clear history Spastroje historikun @@ -5375,21 +5965,23 @@ Are you sure you want to continue with this file? WARNING: You are using an unstable build of KeePassXC. There is a high risk of corruption, maintain a backup of your databases. This version is not meant for production use. - + KUJDES: Po përdorni një montim të paqëndrueshëm të KeePassXC-së. +Ka një rrezik të lartë dëmtimi, mbani një kopjeruajtje të bazave tuaja të të dhënave. +Ky version s’është menduar për përdorim të vërtetë. NOTE: You are using a pre-release version of KeePassXC. Expect some bugs and minor issues, this version is meant for testing purposes. - + SHËNIM: Po përdorni një version paraqarkullim të KeePassXC-së. +Prisni ca të meta dhe probleme të vogla, ky version është menduar për qëllime testimi. - WARNING: Your Qt version may cause KeePassXC to crash with an On-Screen Keyboard. -We recommend you use the AppImage available on our downloads page. - + No Tags + Pa Etiketa Restore Entry(s) - + Riktheje ZërinRiktheji Zërat Settings @@ -5401,23 +5993,27 @@ We recommend you use the AppImage available on our downloads page. Would you like KeePassXC to check for updates on startup? - + Doni që KeePassXC-ja gjatë nisjes të kontrollojë për përditësime? You can always check for updates manually from the application menu. - + Mundeni përherë të kontrolloni dorazi për përditësime, që nga menuja e aplikacionit. Toggle window - Hap/Mbyll dritare + Shfaq/Fshih dritare Quit KeePassXC Mbylle KeePassXC-ën + + %1 Entry(s) + %1 Zë%1 Zëra + Please present or touch your YubiKey to continue… - + Ju lutemi, që të vazhdohet, paraqitni, ose prekni YubiKey-n tuaj… Restart Application? @@ -5425,38 +6021,314 @@ We recommend you use the AppImage available on our downloads page. You must restart the application to apply this setting. Would you like to restart now? - - - - Tags - Etiketa - - - No Tags - Pa Etiketa - - - %1 Entry(s) - %1 Zë%1 Zë - - - Copy Password and TOTP - - - - &XML File… - Kartelë &XML… - - - XML File… - Kartelë XML… - - - Copy &URL - + Që të aplikohet ky rregullim duhet të rinisni aplikacionin. Doni të riniset tani? Allow Screen Capture + Lejo Regjistrim Ekrani + + + 1Password 1PUX... + 1Password 1PUX… + + + Import a 1Password 1PUX file + Importoni një kartelë 1Password 1PUX + + + Import… + Importoni… + + + Passkeys… + Kyçkalime… + + + Import Passkey + Importoni Kyçkalim + + + Remote S&ync… + &Njëkohësim i Largët… + + + Quit Application + Mbylle Aplikacionin + + + Open About Dialog + Hap Dialogun “Mbi” + + + Open Database + Hap Bazë të Dhënash + + + Create Database + Krijo Bazë të Dhënash + + + Merge From Database + Përzieni Prej Baze të Dhënash + + + Create Entry + Krijoni Zë + + + Edit Entry + Përpunoni Zërin + + + Delete Entry + Fshini Zë + + + Create Group + Krijoni Grup + + + Edit Group + Përpunoni Grup + + + Delete Group + Fshije Grupin + + + Download All Favicons + Shkarkoji Krejt Favikonat + + + Sort Groups A-Z + Renditi Grupet sipas A-Z + + + Sort Groups Z-A + Renditi Grupet sipas Z-A + + + Save Database As + Ruaje Bazën e të Dhënave Si + + + Show Database Security + Shfaq Siguri Baze të Dhënash + + + Show Database Reports + Shfaq Raporte Baze të Dhënash + + + Show Database Settings + Shfaq Rregullime Baze të Dhënash + + + Show Passkeys + Shfaq Kyçkalime + + + Clone Entry + Klonoje Zërin + + + Move Entry Up + Ngjite Zërin Sipër + + + Move Entry Down + Zbrite Zërin Poshtë + + + Copy Username + Kopjo Emër Përdoruesi + + + Copy Password + Kopjo Fjalëkalimin + + + Show Application Settings + Shfaq Rregullime Aplikacioni + + + Show Password Generator + Shfaq Prodhues Fjalëkalimesh + + + Remove Passkey From Entry + Hiq Kyçkalim Nga Zëri + + + Perform Auto-Type: {USERNAME} + Kryej Vetë-shtypje: {USERNAME} + + + Perform Auto-Type: {USERNAME}{ENTER} + Kryej Vetë-shtypje: {USERNAME}{ENTER} + + + Perform Auto-Type: {PASSWORD} + Kryej Vetë-shtypje: {PASSWORD} + + + Perform Auto-Type: {PASSWORD}{ENTER} + Kryej Vetë-shtypje: {PASSWORD}{ENTER} + + + Perform Auto-Type: {TOTP} + Kryej Vetë-shtypje: {TOTP} + + + Copy Title + Kopjo Titullin + + + Copy URL + Kopjo URL-në + + + Copy Notes + Kopjo Shënime + + + Export to CSV + Eksportoje si CSV + + + Export to HTML + Eksportoje si HTML + + + Import KeePass1 Database + Importo Bazë të Dhënash Keepass 1 + + + Import 1Password Vault + Importo Kasafortë 1Password + + + Import CSV File + Importo Kartelë CSV + + + Show TOTP QR Code + Shfaq Kod QR TOTP + + + Set up TOTP + Ujdisni TOTP + + + Empty Recycle Bin + Zbraz Koshin e Riciklimeve + + + Open Donation Website + Hap Sajt Dhurimesh + + + Open Bug Report + Hap Njoftim të Metash + + + Open Online Documentation + Hap Dokumentin Në Internet + + + Open Keyboard Shortcuts Guide + Hap Udhërrëfyes Shkurtoresh Tastiere + + + Save Database Backup + Ruani Kopjeruajtje Baze të Dhënash + + + SSH Agent: Add Key + Agjent SSH: Shtoni Kyç + + + SSH Agent: Remove Key + Agjent SSH: Hiqni Kyç + + + Toggle Compact Mode + Aktivizo/Çaktivizo Mënyrën Kompakte + + + Set Theme: Automatic + Caktoni Temë: Automatikisht + + + Set Theme: Light + Caktoni Temë: E çelët + + + Set Theme: Dark + Caktoni Temë: E errët + + + Set Theme: Classic + Caktoni Temë: Klasike + + + Toggle Show Menubar + Shfaq/Fshih Shtyllë menush + + + Toggle Show Toolbar + Shfaq/Fshih Panel + + + Toggle Show Preview Panel + Shfaq/Fshih Panel Paraparjesh + + + Toggle Always on Top + Shfaq/Fshih “Përherë Sipër” + + + Toggle Hide Usernames + Shfaq/Fshih “Fshihi Emrat e Përdoruesve” + + + Toggle Hide Passwords + Shfaq/Fshih “Fshihi Fjalëkalimet” + + + Export to XML + Eksportoje si XML + + + Toggle Allow Screen Capture + Aktivizo/Çaktivizo “Lejo Regjistrim Ekrani” + + + Show Group Panel + Shfaq Panel Grupesh + + + Toggle Show Group Panel + Shfaq/Fshih Panel Grupesh + + + Setup Remote Sync… + Ujdisni Njëkohësim të Largët… + + + Password Generator + + + + E&xpire Entry… + + + + Clear SSH Agent + + + + Clear all identities in ssh-agent @@ -5495,78 +6367,58 @@ We recommend you use the AppImage available on our downloads page. Reset - + Riktheje te parazgjedhja Reset any remembered decisions for this application - + Rikthe te parazgjedhje cilindo vendim të mbajtur mend për këtë aplikacion Merger Creating missing %1 [%2] - + Po krijohet %1 [%2] që mungon Relocating %1 [%2] - + Po zhvendoset %1 [%2] Overwriting %1 [%2] Po mbishkruhet %1 [%2] - - older entry merged from database "%1" - - - - Adding backup for older target %1 [%2] - - - - Adding backup for older source %1 [%2] - - - - Reapplying older target entry on top of newer source %1 [%2] - - - - Reapplying older source entry on top of newer target %1 [%2] - - Synchronizing from newer source %1 [%2] - + Po njëkohësohet prej burimi më të ri %1 [%2] Synchronizing from older source %1 [%2] - + Po njëkohësohet prej burimi më të vjetër %1 [%2] Deleting child %1 [%2] - + Po fshihet pjella %1 [%2] Deleting orphan %1 [%2] - + Po fshihet %1 jetim [%2] Changed deleted objects - + U ndryshuan objekte të fshirë Adding missing icon %1 - + Po shtohet ikonë %1 që mungon Removed custom data %1 [%2] - + U hoqën të dhëna vetjake %1 [%2] Adding custom data %1 [%2] - + U shtuan të dhëna vetjake %1 [%2] @@ -5578,14 +6430,14 @@ We recommend you use the AppImage available on our downloads page. Root Root group - + Rrënjë NewDatabaseWizardPage WizardPage - + Faqe Ndihmësi Encryption Settings @@ -5593,15 +6445,7 @@ We recommend you use the AppImage available on our downloads page. Here you can adjust the database encryption settings. Don't worry, you can change them later in the database settings. - - - - Advanced Settings - Rregullime të Mëtejshme - - - Simple Settings - Rregullime Bazë + Këtu mund të përimtoni rregullime fshehtëzimi bazash të dhënash. Mos u merakosni, mund t’i ndryshoni më vonë te rregullimet e bazës së të dhënave. @@ -5612,7 +6456,7 @@ We recommend you use the AppImage available on our downloads page. A set of credentials known only to you that protects your database. - + Një grup kredencialesh që i dini vetëm ju, që mbrojnë bazën tuaj të të dhënave. @@ -5623,7 +6467,7 @@ We recommend you use the AppImage available on our downloads page. Here you can adjust the database encryption settings. Don't worry, you can change them later in the database settings. - + Këtu mund të përimtoni rregullime fshehtëzimi bazash të dhënash. Mos u merakosni, mun t’i ndryshoni më vonë te rregullimet e bazës së të dhënave. @@ -5634,6 +6478,25 @@ We recommend you use the AppImage available on our downloads page. Please fill in the display name and an optional description for your new database: + Ju lutemi, plotësoni emrin për në ekran dhe një përshkrim opsional për bazën tuaj të re të të dhënave: + + + + NewEntryAttachmentsDialog + + Attachment name cannot be empty + + + + Attachment with the same name already exists + + + + Save attachment + + + + New entry attachment @@ -5656,23 +6519,23 @@ We recommend you use the AppImage available on our downloads page. OpData01 Invalid OpData01, does not contain header - + OpData01 të pavlefshme, s’përmban krye Unable to read all IV bytes, wanted 16 but got %1 - + S’arrihet të lexohen krejt bajtet e Gatitjes së Vektorit, duheshin 16, por u morën %1 Unable to init cipher for opdata01: %1 - + S’arrihet të gatitet shifër për opdata01: %1 Unable to read all HMAC signature bytes - + S’arrihet të lexohen krejt bajtet e nënshkrimit HMAC Malformed OpData01 due to a failed HMAC - + OpData01 të keqformuara, për shkak të një HMAC-u të dështuar Unable to process clearText in place @@ -5680,15 +6543,7 @@ We recommend you use the AppImage available on our downloads page. Expected %1 bytes of clear-text, found %2 - - - - - OpVaultOpenWidget - - Read Database did not produce an instance -%1 - + Priteshin %1 bajte teksti të lexueshëm, u morën %2 @@ -5707,22 +6562,22 @@ We recommend you use the AppImage available on our downloads page. Directory .opvault/default must be readable - + Drejtoria .opvault/default duhet të jetë e lexueshme Unable to decode masterKey: %1 - + S’arrihet të shkodohet masterKey: %1 Unable to derive master key: %1 - + S’arrihet të derivohet kyç i përgjithshëm: %1 OpenSSHKey Invalid key file, expecting an OpenSSH key - + Kartelë e pavlefshme kyçesh, pritej një kyç OpenSSH PEM boundary mismatch @@ -5730,7 +6585,7 @@ We recommend you use the AppImage available on our downloads page. Base64 decoding failed - + Dështoi shkodim Base64 Key file way too small. @@ -5742,15 +6597,15 @@ We recommend you use the AppImage available on our downloads page. Found zero keys - + U gjetën zero kyçe Failed to read public key. - + S’u arrit të lexohej kyç publik. Corrupted key file, reading private key failed - + Kartelë kyçi e dëmtuar, leximi i kyçit privat dështoi Unsupported key type: %1 @@ -5764,13 +6619,17 @@ We recommend you use the AppImage available on our downloads page. Unknown cipher: %1 Shifër e panjohur: %1 + + AES-256/GCM is currently not supported + AES-256/GCM hëpërhë s’mbulohet + Passphrase is required to decrypt this key - + Që të shfshehtëzohet ky kyç, lypset frazëkalim Key derivation failed: %1 - + Derivimi i kyçit dështoi: %1 Cipher IV is too short for MD5 kdf @@ -5814,23 +6673,198 @@ We recommend you use the AppImage available on our downloads page. Can't write public key as it is empty - + S’shkruhet dot kyç publik, ngaqë është i zbrazët Unexpected EOF when writing public key - + EOF i papritur, kur shkruhej kyç publik Can't write private key as it is empty - + S’shkruhet dot kyç privat, ngaqë është i zbrazët Unexpected EOF when writing private key + EOF i papritur, kur shkruhej kyç privat + + + (encrypted) + (i fshehtëzuar) + + + + OpenSSHKeyGenDialog + + SSH Key Generator + Prodhues Kyçi SSH + + + Type + Lloj + + + Bits + Bite + + + Comment + Koment + + + + PasskeyExportDialog + + KeePassXC - Passkey Export + KeePassXC - Eksportim Kyçkalimi + + + Filenames will be generated with title and .passkey file extension. + Emrat e kartelave do të prodhohen me titull dhe zgjatim .passkey për kartelat. + + + Export entries + Eksporto zëra + + + Export Selected + U përzgjodh Eksport + + + Cancel + Anuloje + + + Export to folder + Eksportoje në dosje + + + Export the following passkey entries. + Eksporto zërat vijues të kyçkalimeve. + + + + PasskeyExporter + + KeePassXC: Passkey Export + KeePassXC: Eksportim Kyçkalimi + + + File "%1.passkey" already exists. +Do you want to overwrite it? + + Ka tashmë një kartelë “%1.passkey”. +Doni të mbishkruhet? + + + + Cannot open file + S’hapet dot kartela + + + Cannot open file "%1" for writing. + S’hapet dot kartela “%1” për shkrim. + + + Cannot write to file + S’shkruhet dot te kartela + + + + PasskeyImportDialog + + KeePassXC - Passkey Import + KeePassXC - Importim Kyçkalimi + + + Username: %1 + Emër Përdoruesi: %1 + + + Group + Grup + + + Database + Bazë të dhënash + + + Import Passkey + Importoni Kyçkalim + + + Import + Importo + + + Cancel + Anuloje + + + Entry + + + + Create new entry + Krijoni zë të ri + + + Relying Party: %1 - AES-256/GCM is currently not supported - AES-256/GCM hëpërhë s’mbulohet + Import the following passkey: + Importo kyçkalimin vijues: + + + Import the following passkey to this entry: + Importo kyçkalimin vijues te ky zë: + + + Default passkeys group (Imported Passkeys) + Grup parazgjedhje kyçkalimesh (Kyçkalime të Importuar) + + + + PasskeyImporter + + Passkey file + Kartelë kyçi + + + All files + Krejt kartelat + + + Cannot open file + S’hapet dot kartela + + + Cannot open file "%1" for reading. + S’hapet dot kartela “%1” për lexim. + + + Open passkey file + Hap kartelë kyçi + + + Cannot import passkey + S’importohet dot kyçkalim + + + Cannot import passkey file "%1". Data is missing. + S’importohet dot kartelë kyçkalimi “%1”. Mungojnë të dhëna. + + + Cannot import passkey file "%1". +The following data is missing: +%2 + S’importohet dot kartelë kyçkalimi “%1”. +Mungojnë të dhënat vijues: +%2 + + + Cannot import passkey file "%1". Private key is missing or malformed. + S’importohet dot kartelë kyçkalimi “%1”. Mungon, ose është i keqformuar kyçi privat. @@ -5873,7 +6907,7 @@ We recommend you use the AppImage available on our downloads page. <p>A password is the primary method for securing your database.</p><p>Good passwords are long and unique. KeePassXC can generate one for you.</p> - + <p>Një fjalëkalim përbën metodën parësore për sigurimin e bazës suaj të të dhënave.</p><p>Fjalëkalimet e mirë janë të gjatë dhe unikë. KeePassXC-ja mund të prodhojë një të tillë për ju.</p> Passwords do not match. @@ -5969,7 +7003,7 @@ We recommend you use the AppImage available on our downloads page. Extended ASCII - ASCII e Zzgjeruar + ASCII e zgjeruar Braces @@ -5981,7 +7015,7 @@ We recommend you use the AppImage available on our downloads page. Additional characters to use for the generated password - + Shenja shtesë për tu përdorur për fjalëkalimin e prodhuar Additional characters @@ -5989,7 +7023,7 @@ We recommend you use the AppImage available on our downloads page. Add non-hex letters to "do not include" list - + Shto shkronja jo gjashtëmbëdhjetëshe te listë “mos përfshi” Hex Passwords @@ -6001,7 +7035,7 @@ We recommend you use the AppImage available on our downloads page. Character set to exclude from generated password - + Shenja për t’u përjashtuar nga fjalëkalimi i prodhuar Excluded characters @@ -6017,7 +7051,7 @@ We recommend you use the AppImage available on our downloads page. Pick characters from every group - + Merr shenja nga çdo grup Passphrase @@ -6029,19 +7063,15 @@ We recommend you use the AppImage available on our downloads page. Wordlist: - + Listë fjalësh: Word Count: Numër Fjalësh: - - Character Count: - Numër Shenjash: - Word Case: - + Shkronja për Fjalën: Delete selected wordlist @@ -6051,10 +7081,6 @@ We recommend you use the AppImage available on our downloads page. Add custom wordlist Shtoni listë vetjake fjalësh - - character - shenjë - Close Mbylle @@ -6081,7 +7107,7 @@ We recommend you use the AppImage available on our downloads page. Title Case - + Shkronja për Titullin: (SYSTEM) @@ -6091,6 +7117,30 @@ We recommend you use the AppImage available on our downloads page. Entropy: %1 bit Entropi: %1 bit + + Password Quality: %1 + Cilësi Fjalëkalimesh: %1 + + + Poor + Password quality + Shumë i dobët + + + Weak + Password quality + I dobët + + + Good + Password quality + I mirë + + + Excellent + Password quality + I shkëlqyer + Confirm Delete Wordlist Ripohoni Fshirje Liste Fjalësh @@ -6117,12 +7167,13 @@ We recommend you use the AppImage available on our downloads page. Overwrite Wordlist? - Të mbishkruhet Listë Fjalësh? + Të mbishkruhet Listë Fjalësh? Wordlist "%1" already exists as a custom wordlist. Do you want to overwrite it? - + Lista e fjalëve “%1”ekziston si një listë vetjake fjalësh. +Doni të mbishkruhet? Failed to add wordlist @@ -6130,39 +7181,27 @@ Do you want to overwrite it? Logograms - + Logograme Special Characters Shenja Speciale - Password Quality: %1 - Cilësi Fjalëkalimesh: %1 - - - Poor - Password quality - Shumë i dobët - - - Weak - Password quality - I dobët - - - Good - Password quality + passwordLength - Excellent - Password quality - + Characters: %1 + Shenja: %1 - Excluded characters: "0", "1", "l", "I", "O", "|", "﹒" - + MIXED case + Shkronja TË PËRZIERA + + + Excluded characters: "0", "1", "l", "I", "O", "|", "﹒", "B", "8", "G", "6" + Shenja të përjashtuara: “0”, “1”, “l”, “I”, “O”, “|”, “﹒”, “B”, “8”, “G”, “6” @@ -6177,7 +7216,7 @@ Do you want to overwrite it? Toggle Password (%1) - + Shfaq/Fshih Fjalëkalim (%1) Generate Password (%1) @@ -6204,16 +7243,16 @@ Do you want to overwrite it? Good Password quality - + I mirë Excellent Password quality - + I shkëlqyer - Toggle password visibilty using Control + H. Open the password generator using Control + G. - + Toggle password visibility using Control + H. Open the password generator using Control + G. + Ndryshoni dukshmërinë e fjalëkalimit duke përdorur Ctrl + H. Hapni prodhuesin e fjalëkalimeve duke përdorur Ctrl + G. @@ -6224,13 +7263,28 @@ Do you want to overwrite it? Select characters to type, navigate with arrow keys, Ctrl + S submits. - + Përzgjidhni shenja për shtypje, lëvizni me tastet shigjetë, Ctrl + S bën parashtrimin. Press &Tab between characters Shtypni tastin &Tab mes shenjave + + PreviewEntryAttachmentsDialog + + Preview entry attachment + + + + No preview available + + + + Image format not supported + + + QMessageBox @@ -6269,6 +7323,10 @@ Do you want to overwrite it? Continue Vazhdo + + Continue with weak password + Vazhdo me fjalëkalim të dobët + QObject @@ -6298,7 +7356,7 @@ Do you want to overwrite it? KeePassXC association failed, try again - + Përshoqërimi i KeePassXC-së dështoi, riprovoni Encryption key is not recognized @@ -6350,7 +7408,7 @@ Do you want to overwrite it? Username for the entry. - Emër përdoruesi për zërin.Zë + Emër përdoruesi për zërin. username @@ -6406,11 +7464,11 @@ Do you want to overwrite it? Successfully added entry %1. - + U shtua me sukses zëri %1. Adds a new group to a database. - + Shton një grup të ri te një bazë të dhënash. Path of the group to add. @@ -6430,7 +7488,7 @@ Do you want to overwrite it? Check if any passwords have been publicly leaked. FILENAME must be the path of a file listing SHA-1 hashes of leaked passwords in HIBP format, as available from https://haveibeenpwned.com/Passwords. - + Kontrolloni nëse ka rrjedhur publikisht çfarëdo fjalëkalimi. EMËRKARTELE duhet të jetë shtegu i një kartele që radhit hashe SHA-1 të fjalëkalimeve që janë komprometuar, në format, si gjenden te https://haveibeenpwned.com/Passwords. FILENAME @@ -6438,7 +7496,7 @@ Do you want to overwrite it? Path to okon-cli to search a formatted HIBP file - + Shteg për te okon-cli për të kërkuar një kartelë të formatuar si HIBP okon-cli @@ -6446,7 +7504,7 @@ Do you want to overwrite it? Analyze passwords for weaknesses and problems. - + Analizoni fjalëkalime për dobësi dhe probleme. Cannot find HIBP file: %1 @@ -6454,7 +7512,7 @@ Do you want to overwrite it? Evaluating database entries using okon… - + Po peshohen zëra baze të dhënash duke përdorur okon… Failed to open HIBP file %1: %2 @@ -6462,15 +7520,15 @@ Do you want to overwrite it? Evaluating database entries against HIBP file, this will take a while… - + Po peshohen zëra baze të dhënash kundrejt kartele HIBP, kjo do të zgjasë ca… Password for '%1' has been leaked %2 time(s)! - + Fjalëkalimi për “%1” ka rrjedhur %2 herë!Fjalëkalimi për “%1” ka rrjedhur %2 herë! Password for '%1' has been leaked! - + Fjalëkalimi për “%1” ka rrjedhur! Export an attachment of an entry. @@ -6486,11 +7544,11 @@ Do you want to overwrite it? Path to which the attachment should be exported. - + Shteg te i cili duhet eksportuar bashkëngjitja. Could not find entry with path %1. - + S’u gjet dot zë me shtegun %1. Could not find attachment with name %1. @@ -6498,15 +7556,15 @@ Do you want to overwrite it? No export target given. Please use '--stdout' or specify an 'export-file'. - + S’u dha objektiv eksportimi. Ju lutemi, përdorni “--stdout”, ose specifikoni një “kartelë-eksportimi”. Could not open output file %1. - + S’u hap dot kartela output %1. Successfully exported attachment %1 of entry %2 to %3. - + U eksportua me sukses bashkëngjitja %1 e zërit %2 te %3. Overwrite existing attachments. @@ -6538,7 +7596,7 @@ Do you want to overwrite it? Successfully imported attachment %1 as %2 to entry %3. - + U importua me sukses bashkëngjitja %1 e zërit %2 te %3. Remove an attachment of an entry. @@ -6550,20 +7608,20 @@ Do you want to overwrite it? Successfully removed attachment %1 from entry %2. - + U hoq me sukses bashkëngjitja %1 nga zëri %2. Copy the given attribute to the clipboard. Defaults to "password" if not specified. Don't translate "password", it refers to the attribute. - + Kopjoje në të papastër atributin e dhënë. Si parazgjedhje merr vlerën “password”, nëse nuk specifikohet. Copy the current TOTP to the clipboard (equivalent to "-a totp"). - + Kopjo në të papastër TOTP e tanishëm (e njëvlershme me “-a totp”). Must match only one entry, otherwise a list of possible matches is shown. - + Duhet të gjejë përkim vetëm me një zë, përndryshe shfaqet një listë përkimesh të mundshëm. Copy an entry's attribute to the clipboard. @@ -6572,11 +7630,11 @@ Do you want to overwrite it? Path of the entry to clip. clip = copy to clipboard - + Shteg zëri për t’u kopjuar në të papastër. Timeout before clearing the clipboard (default is %1 seconds, set to 0 for unlimited). - + Mbarim kohe para se të pastrohet e papastra (parazgjedhja është %1 sekonda, vëreni 0 për të qenë e pakufizuar). Invalid timeout value %1. @@ -6596,15 +7654,15 @@ Do you want to overwrite it? ERROR: Please specify one of --attribute or --totp, not both. - + GABIM: Ju lutemi, specifikoni një nga --attribute ose --totp, jo që të dy. Entry with path %1 has no TOTP set up. - + Zëri me shtegun %1 s’ka TOTP të ujdisur. ERROR: attribute %1 is ambiguous, it matches %2. - + GABIM: atributi %1 është i dykuptimtë, përkon me %2. Attribute "%1" not found. @@ -6648,7 +7706,7 @@ Do you want to overwrite it? Yubikey slot and optional serial used to access the database (e.g., 1:7370001). - + Vend për Yubikey dhe serial opsional të përdorur për të hyrë te baza e të dhënave (p.sh., 1:7370001). slot[:serial] @@ -6662,9 +7720,13 @@ Do you want to overwrite it? Too many arguments provided. U dhanë shumë argumente. + + Path of the database. + Shteg i bazës së të dhënave. + Target decryption time in MS for the database. - + Kohë shfshehtëzimi e synuar, në MS, për bazën e të dhënave. time @@ -6682,17 +7744,13 @@ Do you want to overwrite it? Create a new database. Krijoni bazë të re të dhënash. - - Path of the database. - Shteg i bazës së të dhënave. - Invalid decryption time %1. Kohë e pavlefshme shfshehtëzimi %1. Target decryption time must be between %1 and %2. - + Koha e synuar për shfshehtëzimin duhet të jetë mes %1 dhe %2. Failed to set database password. @@ -6704,19 +7762,19 @@ Do you want to overwrite it? No key is set. Aborting database creation. - + S’është ujdisur ndonjë kyç. Po ndërpritet krijimi i bazës së të dhënave. Benchmarking key derivation function for %1ms delay. - + Po vlerësohet funksioni i derivimit të kyçit për vonesë %1ms. Setting %1 rounds for key derivation function. - + Po caktohen %1 raunde për funksion derivimi kyçesh. error while setting database key derivation settings. - + gabim teksa ujdiseshin rregullime derivimi kyçi baze të dhënash. File %1 already exists. @@ -6730,9 +7788,161 @@ Do you want to overwrite it? Successfully created new database. U krijua me sukses bazë e re të dhënash. + + Unset the password for the database. + Hiqe fjalëkalimin për bazën e të dhënave. + + + Unset the key file for the database. + Hiqe kartelën e kyçit për bazën e të dhënave. + + + Edit a database. + Përpunoni një bazë të dhënash. + + + Cannot use %1 and %2 at the same time. + S’mund të përdoret %1 dhe %2 në të njëjtën kohë. + + + Could not change the database key. + S’u ndryshua dot kyçi i bazës së të dhënave. + + + Database was not modified. + Baza e të dhënave s’u ndryshua. + + + Writing the database failed: %1 + Shkrimi te baza e të dhënave dështoi: %1 + + + Successfully edited the database. + Baza e të dhënave u përpunua me sukses. + + + Cannot remove password: The database does not have a password. + S’hiqet dot fjalëkalim: Baza e të dhënave s’ka fjalëkalim. + + + Cannot remove file key: The database does not have a file key. + S’hiqet dot kyç kartele: Baza e të dhënave s’ka kyç kartele. + + + Loading the new key file failed: %1 + Dështoi ngarkimi i kartelës së re të kyçit: %1 + + + Found unexpected Key type %1 + U gjet lloj i papritur %1 Kyçi + + + Cannot remove all the keys from a database. + S’mund të hiqen krejt kyçet nga një bazë të dhënash. + + + Show a database's information. + Shfaq hollësi të një baze të dhënash. + + + UUID: + UUID: + + + Name: + Emër: + + + Description: + Përshkrim: + + + Cipher: + Shifër: + + + KDF: + FDK: + + + Recycle bin is enabled. + Koshi i hedhurinave është aktivizuar. + + + Recycle bin is not enabled. + Koshi i hedhurinave s’është aktivizuar. + + + Location + Vendndodhje + + + Database created + Baza e të dhënave u krijua + + + Last saved + Ruajtur së fundi më + + + Unsaved changes + Ndryshime të paruajtura + + + yes + po + + + no + jo + + + Number of groups + Numër grupesh + + + Number of entries + Numër zërash + + + Number of expired entries + Numër zërash të skaduar + + + Unique passwords + Fjalëkalime unikë + + + Non-unique passwords + Fjalëkalime jo unikë + + + Maximum password reuse + Maksimum ripërdorimi fjalëkalimi + + + Number of short passwords + Numër fjalëkalimesh të shkurtër + + + Number of weak passwords + Numër fjalëkalimet të dobët + + + Entries excluded from reports + Zëra të përjashtuar nga raporte + + + Average password length + Gjatësi mesatare fjalëkalimesh + + + %1 characters + %1 shenja + Word count for the diceware passphrase. - + Numër fjalësh për frazëkalim Diceware. count @@ -6742,20 +7952,17 @@ Do you want to overwrite it? Wordlist for the diceware generator. [Default: EFF English] - + Listë fjalësh për prodhuesin Diceware. +[Parazgjedhje: EFF English] Generate a new random diceware passphrase. - + Prodho një frazëkalim të ri kuturu Diceware. Invalid word count %1 Numër i pavlefshëm fjalësh %1 - - The word list is too small (< 1000 items) - - Title for the entry. Titull për zërin. @@ -6774,16 +7981,12 @@ Do you want to overwrite it? Not changing any field for entry %1. - + S’po ndryshohet ndonjë fushë për zërin %1. Enter new password for entry: Jepni fjalëkalim të ri për zërin: - - Writing the database failed: %1 - Shkrimi te baza e të dhënave dështoi: %1 - Successfully edited entry %1. Zëri %1 u përpunua me sukses. @@ -6794,7 +7997,7 @@ Do you want to overwrite it? Password for which to estimate the entropy. - + Fjalëkalim për të cilin të vlerësohet entropia. Estimate the entropy of a password. @@ -6818,7 +8021,7 @@ Do you want to overwrite it? Type: Bruteforce - + Lloj: Hyrje me zor Type: Dictionary @@ -6898,19 +8101,15 @@ Do you want to overwrite it? *** Password length (%1) != sum of length of parts (%2) *** - + *** Gjatësi fjalëkalimi (%1) != shuma e gjatësisë së pjesëve (%2) *** Exit interactive mode. - Dil nga mënyra me ndërveprim - - - Format to use when exporting. Available choices are 'xml' or 'csv'. Defaults to 'xml'. - + Dil nga mënyra me ndërveprim. Exports the content of a database to standard output in the specified format. - + Eksportoje lëndën e një bazë të dhënash te output-i standard në formatin e treguar. Unable to export database to XML: %1 @@ -6930,11 +8129,11 @@ Do you want to overwrite it? Use lowercase characters - Përdorni shenja me të vogla + Përdor shenja me të vogla Use uppercase characters - Përdorni shenja me të mëdhaja + Përdor shenja me të mëdha Use numbers @@ -6950,7 +8149,7 @@ Do you want to overwrite it? Exclude character set - + Përjashto grup shenjash chars @@ -6966,7 +8165,7 @@ Do you want to overwrite it? Include characters from every selected group - + Përfshi shenja nga çdo grup i përzgjedhur Generate a new random password. @@ -6978,7 +8177,7 @@ Do you want to overwrite it? Invalid password generator after applying all options - + Prodhues i pavlefshëm fjalëkalimi, pas aplikimit të tërë mundësive Display command help. @@ -6990,11 +8189,11 @@ Do you want to overwrite it? Import the contents of an XML database. - + Importo lëndën e një baze të dhënash XML. Path of the XML database export. - + Shteg eksportimi baze të dhënash XML. Path of the new database. @@ -7008,106 +8207,6 @@ Do you want to overwrite it? Successfully imported database. U importua me sukses bazë të dhënash. - - Show a database's information. - Shfaq hollësi të një baze të dhënash - - - UUID: - UUID: - - - Name: - Emër: - - - Description: - Përshkrim: - - - Cipher: - Shifër: - - - KDF: - FDK: - - - Recycle bin is enabled. - Koshi i hedhurinave është aktivizuar. - - - Recycle bin is not enabled. - Koshi i hedhurinave s’është aktivizuar. - - - Location - Vendndodhje - - - Database created - Baza e të dhënave u krijua - - - Last saved - - - - Unsaved changes - Ndryshime të paruajtura - - - yes - po - - - no - jo - - - Number of groups - Numër grupesh - - - Number of entries - Numër zërash - - - Number of expired entries - Numër zërash të skaduar - - - Unique passwords - Fjalëkalime unikë - - - Non-unique passwords - Fjalëkalime jo unikë - - - Maximum password reuse - Maksimum ripërdorimi fjalëkalimi - - - Number of short passwords - Numër fjalëkalimesh të shkurtër - - - Number of weak passwords - Numër fjalëkalimet të dobët - - - Entries excluded from reports - Zëra të përjashtuar nga raporte - - - Average password length - Gjatësi mesatare fjalëkalimesh - - - %1 characters - %1 shenja - Unknown command %1 Urdhër %1 i panjohur @@ -7156,23 +8255,23 @@ Urdhra të gatshëm: Use the same credentials for both database files. - + Përdor të njëjtat kredenciale për të dyja kartelat e bazës së të dhënave. Key file of the database to merge from. - Kartelë kyçesh i bazës së të dhënave prej nga të bëhet përzierja. + Kartelë kyç i bazës së të dhënave prej nga të bëhet përzierja. Deactivate password key for the database to merge from. - + Çaktivizoje kyçin e fjalëkalimit për bazën e të dhënave prej nga bëhet përzierje. Only print the changes detected by the merge operation. - + Shtyp vetëm ndryshimet e pikasura nga veprimi i përzierjes. Yubikey slot for the second database. - + Vend Yubikey për bazën e dytë të të dhënave. slot @@ -7254,7 +8353,7 @@ Urdhra të gatshëm: Cannot remove root group from database. - + S’hiqet dot grupi rrënjë nga baza e të dhënave. Successfully recycled group %1. @@ -7278,7 +8377,11 @@ Urdhra të gatshëm: Show the protected attributes in clear text. - + Atributet e mbrojtura shfaqi si tekst i lexueshëm. + + + Show all the attributes of the entry. + Shfaq krejt atributet e zërit. Show the attachments of the entry. @@ -7286,7 +8389,7 @@ Urdhra të gatshëm: Names of the attributes to show. This option can be specified more than once, with each attribute shown one-per-line in the given order. If no attributes are specified, a summary of the default attributes is given. - + Emrat e atributeve për t’u shfaqur. Kjo mundësi mund të jepet më shumë se një herë, me çdo atribut të shfaqur një për rresht sipas rendit të dhënë. Nëse nuk specifikohen atribute, jepet një përmbledhje e atributeve parazgjedhje. attribute @@ -7337,14 +8440,21 @@ Urdhra të gatshëm: stop supporting in the future. Please consider generating a new key file. - + KUJDES: po përdorni një format të vjetër kartelash kyçi, të cilin KeePassXC-ja mund +të reshtë së mbuluari në të ardhmen. + +Ju lutemi, shihni mundësinë e prodhimit të një kartele të re kyçi. Invalid YubiKey slot %1 - + Vend i pavlefshëm për YubiKey %1 Invalid YubiKey serial %1 + Serial i pavlefshëm për YubiKey %1 + + + Please present or touch your YubiKey to continue. @@ -7353,7 +8463,7 @@ Please consider generating a new key file. Do you want to create a database with an empty password? [y/N]: - + Doni të krijohet një bazë të dhënash me një fjalëkalim të zbrazët? [y/N]: Repeat password: @@ -7365,28 +8475,29 @@ Please consider generating a new key file. No program defined for clipboard manipulation - + S’ka të përcaktuar program për manipulim të papastre All clipping programs failed. Tried %1 - + Dështuan krejt programet e kopjimit në të papastër. U provuan %1 + Creating KeyFile %1 failed: %2 - + Krijimi i Kartelës së kyçit %1 dështoi: %2 Loading KeyFile %1 failed: %2 - + Ngarkimi Kartelës së kyçit %1 dështoi: %2 HIBP file, line %1: parse error - + Kartelë HIBP, rreshti %1: gabim analizimi To use okon, you must provide a post-processed file (e.g. file.okon) - + Që të përdorni okon, duhet të jepni një kartelë të pas-përpunuar (p.sh. kartelë.okon) Could not start okon process: %1 @@ -7394,11 +8505,11 @@ Please consider generating a new key file. Error: okon process did not finish - + Gabim: procesi okon s’përfundoi Failed to load okon processed database: %1 - + S’u arrit të ngarkohet bazë të dhënash e përpunuar me okon: %1 Very weak password @@ -7414,7 +8525,7 @@ Please consider generating a new key file. Used in %1/%2 - + Përdorur te %1/%2 Password is used %1 time(s) @@ -7438,7 +8549,7 @@ Please consider generating a new key file. Password expires in %1 day(s) - Fjalëkalim skadon pas %1 ditëFjalëkalim skadon pas %1 ditë + Fjalëkalim skadon pas %1 diteFjalëkalim skadon pas %1 ditësh Password will expire soon @@ -7450,7 +8561,7 @@ Please consider generating a new key file. Build Type: %1 - + Lloj Montimi: %1 Revision: %1 @@ -7458,7 +8569,7 @@ Please consider generating a new key file. Distribution: %1 - + Shpërndarje: %1 Debugging mode is disabled. @@ -7472,7 +8583,9 @@ Please consider generating a new key file. Operating system: %1 CPU architecture: %2 Kernel: %3 %4 - + Sistem operativ: %1 +Arkitekturë CPU-je: %2 +Kernel: %3 %4 Auto-Type @@ -7484,7 +8597,7 @@ Kernel: %3 %4 KeeShare - + KeeShare YubiKey @@ -7532,7 +8645,7 @@ Kernel: %3 %4 Botan library must be at least %1, found %2.%3.%4 - + Bilbioteka Botan duhet të jetë të paktën %1, u gjet %2.%3.%4 Cryptographic libraries: @@ -7544,15 +8657,15 @@ Kernel: %3 %4 Argon2%1 (%2 rounds, %3 KB) - + Argon2%1 (%2 raunde, %3 KB) SymmetricCipher::init: Invalid cipher mode. - + SymmetricCipher::init: Mënyrë shifre e pavlefshme. SymmetricCipher::init: Invalid IV size of %1 for %2. - + SymmetricCipher::init: Madhësi e pavlefshme IV prej %1 për %2. Cipher not initialized prior to use. @@ -7560,11 +8673,11 @@ Kernel: %3 %4 Cannot process 0 length data. - + S’mund të përpunohen të dhëna me gjatësi 0. unknown executable (DBus address %1) - + i ekzekutueshëm i panjohur (adresë DBus %1) %1 (invalid executable path) @@ -7582,18 +8695,6 @@ Kernel: %3 %4 file empty kartelë e zbrazët - - malformed string - varg i keqformuar - - - missing closing quote - mungon kllapë mbyllëse - - - %1: (row, col) %2,%3 - - AES 256-bit AES 256-bit @@ -7624,15 +8725,15 @@ Kernel: %3 %4 Existing single-instance lock file is invalid. Launching new instance. - + Kartela e kyçjes për instancë njëshe ekzistuese është e pavlefshme. Po niset instancë e re. The lock file could not be created. Single-instance mode disabled. - + S’u krijua dot kartela e kyçjes. U çaktivizua mënyra instancë njëshe. Clearing the clipboard in %1 second(s)… - + Po spastrohet e papastra pas %1 sekonde…Po spastrohet e papastra pas %1 sekondash… Group @@ -7668,17 +8769,17 @@ Kernel: %3 %4 Benchmark %1 delay - + Vlerëso vonesë %1 %1 ms milliseconds - + %1 ms%1 ms %1 s seconds - + %1 s%1 s Do you really want to delete the entry "%1" for good? @@ -7686,7 +8787,7 @@ Kernel: %3 %4 Do you really want to delete %n entry(s) for good? - Doni vërtet të fshihet përgjithmonë %n zë(ra)?Doni vërtet të fshihet përgjithmonë %n zë(ra)? + Doni vërtet të fshihet përgjithmonë %n zë?Doni vërtet të fshihet përgjithmonë %n zëra? Delete entry(s)? @@ -7694,11 +8795,11 @@ Kernel: %3 %4 Do you really want to move entry "%1" to the recycle bin? - + Doni vërtet të shpihet zëri “%1” te koshi i riciklimeve? Do you really want to move %n entry(s) to the recycle bin? - + Doni vërtet të shpihet %n zë te koshi i riciklimeve?Doni vërtet të shpihet %n zëra te koshi i riciklimeve? Move entry(s) to recycle bin? @@ -7710,7 +8811,7 @@ Kernel: %3 %4 Entry "%1" has %2 reference(s). Do you want to overwrite references with values, skip this entry, or delete anyway? - + Zëri “%1” ka %2 referencë(a). Doni të mbishkruhen referencat me vlera, të anashkalohet ky zë, apo të fshihet sido qoftë?Zëri “%1” ka %2 referenca. Doni të mbishkruhen referencat me vlera, të anashkalohet ky zë, apo të fshihet sido qoftë? User name @@ -7738,19 +8839,19 @@ Kernel: %3 %4 Checksum mismatch! Key file may be corrupt. - + Mospërputhje checksum-i! Kartela e kyçit mund të jetë e dëmtuar. Unexpected key file data! Key file may be corrupt. - + Të dhëna të papritura kartele kyçi! Kartela e kyçit mund të jetë e dëmtuar. KeePassXC - cross-platform password manager - + KeePassXC - përgjegjës ndërplatformësh fjalëkalimesh filenames of the password databases to open (*.kdbx) - + emrat e kartelave të bazës së të dhënave të fjalëkalimeve për t’u hapur (*.kdbx) path to a custom config file @@ -7772,18 +8873,18 @@ Kernel: %3 %4 read password of the database from stdin fjalëkalimin e bazës së të dhënave lexoje prej stdin-it - - Locked databases. - - Database failed to lock. - S’u arrit të kyçej bazë të dhënash + S’u arrit të kyçej bazë të dhënash. Another instance of KeePassXC is already running. Ka tashmë në xhirim e sipër një instancë të KeePassXC-së. + + KeePassXC is not running. No open database to lock + KeePassXC-ja s’po xhiron. S’ka të hapur bazë të dhënash, që të kyçet + Fatal error while testing the cryptographic functions. Gabim fatal teksa testoheshin funksione kriptografike. @@ -7808,15 +8909,15 @@ Kernel: %3 %4 Failed to create Windows Hello credential. - + S’u arrit të krijohet kredencial Windows Hello. Failed to sign challenge using Windows Hello. - + S’u arrit të nënshkruhet sfidë duke përdorur Windows Hello. Warning: Failed to block screenshot capture on a top-level window. - + Kujdes: S’u arrit të bllokohet bërje fotoje ekrani në një dritare të nivelit të epërm. Invalid Cipher @@ -7827,74 +8928,301 @@ Kernel: %3 %4 FDK i Pavlefshëm - Please present or touch your YubiKey to continue. - - - - Show all the attributes of the entry. - Shfaq krejt atributet e zërit. - - - Edit a database. - Përpunoni një bazë të dhënash. - - - Could not change the database key. - S’u ndryshua dot kyçi i bazës së të dhënave. - - - Database was not modified. - Baza e të dhënave s’u ndryshua. - - - Successfully edited the database. - Baza e të dhënave u përpunua me sukses. - - - Loading the new key file failed: %1 - Dështoi ngarkimi i kartelës së re të kyçit: %1 - - - Unset the password for the database. - Hiqe fjalëkalimin për bazën e të dhënave. - - - Unset the key file for the database. - Hiqe kartelën e kyçit për bazën e të dhënave. - - - Cannot use %1 and %2 at the same time. - S’mund të përdoret %1 dhe %2 në të njëjtën kohë. - - - Cannot remove all the keys from a database. - - - - Cannot remove password: The database does not have a password. - - - - Cannot remove file key: The database does not have a file key. - - - - Found unexpected Key type %1 - U gjet lloj i papritur %1 Kyçi - - - Set the key file for the database. -This options is deprecated, use --set-key-file instead. - - - - KeePassXC is not running. No open database to lock - + Access to all entries is denied + Është mohuar hyrja te krejt zërat allow screenshots and app recording (Windows/macOS) + lejo foto ekrani dhe regjistrim nga aplikacione (Windows/macOS) + + + Set the key file for the database. +This option is deprecated, use --set-key-file instead. + Ujdisni kartelën kyç për bazën e të dhënave. +Kjo mundësi është nxjerrë nga përdorimi, në vend të saj përdorni --set-key-file. + + + Databases have been locked. + Bazat e të Dhënave janë kyçur. + + + Attestation not supported + + Credential is excluded + Kredenciali është përjashtuar + + + Passkeys request canceled + Kërkesa për kyçkalime u anulua + + + Invalid user verification + Verifikim i pavlefshëm përdoruesi + + + Empty public key + Kyç publik i zbrazët + + + Invalid URL provided + U dha URL e pavlefshme + + + Passkeys + Kyçkalime + + + AES initialization failed + Dështoi gatitja AES + + + AES encrypt failed + Fshehtëzimi AES dështoi + + + Failed to store in Linux Keyring + S’u arrit të depozitohej në Varg Kyçesh Linux + + + Polkit returned an error: %1 + Polkit u përgjigj me një gabim: %1 + + + Could not locate key in keyring + S’u lokalizua dot kyç te varg kyçesh + + + Could not read key in keyring + S’u lexua dot kyç te varg kyçesh + + + AES decrypt failed + Shfshehtëzimi AES dështoi + + + No Polkit authentication agent was available + S’ka agjent mirëfilltësimesh Polkit + + + Polkit authorization failed + Autorizimi Polkit dështoi + + + No Quick Unlock provider is available + + + + Failed to init KeePassXC crypto. + S’u arrit të gatitet kriptografi KeePassXC-je. + + + Failed to encrypt key data. + S’u arrit të fshehtëzohen të dhëna kyçi. + + + Failed to get Windows Hello credential. + S’u arrit të merret kredencial Windows Hello. + + + Failed to decrypt key data. + S’u arrit të shfshehtëzohen të dhëna kyçi. + + + Origin is empty or not allowed + Origjina është e zbrazët, ose nuk lejohet + + + Effective domain is not a valid domain + Përkatësia efektive s’është përkatësi e vlefshme + + + Origin and RP ID do not match + ID-të origjinës dhe RP s’përputhen + + + No supported algorithms were provided + S’u dhanë algoritme të mbuluar + + + Wait for timer to expire + Prisni të skadojë kohëmatësi + + + Challenge is shorter than required minimum length + Sfida është më e shkurtër se gjatësi minimum e domosdoshme + + + user.id does not match the required length + user.id nuk plotëson gjatësinë e domosdoshme + + + Favorite + Tag for favorite entries + Të parapëlqyer + + + File does not exist. + Kartela s’ekziston. + + + Cannot open file: %1 + S’hapet dot kartelë: %1 + + + Cannot parse file: %1 at position %2 + S’analizohet dot kartelë: %1 në pozicionin %2 + + + Failed to decrypt json file: %1 + S’u arrit të shfshehtëzohet kartelë json: %1 + + + Invalid encKeyValidation field + Fushë encKeyValidation e pavlefshme + + + Invalid cipher list within encKeyValidation field + Listë e pavlefshme shifre brenda fushës encKeyValidation + + + Wrong password + Fjalëkalim i gabuar + + + Invalid encrypted data field + Fushë e pavlefshme të dhënash të fshehtëzuara + + + Invalid cipher list within encrypted data field + Listë e pavlefshme shifre brenda fushe të dhënash të fshehtëzuara + + + Cannot initialize cipher + S’gatitet dot shifër + + + Cannot decrypt data + S’shfshehtëzohen dot të dhëna + + + Bitwarden Import + Importim Bitwarden + + + Archived + Tag for archived entries + Të arkivuar + + + Invalid 1PUX file format: Not a valid ZIP file. + Format i pavlefshëm kartele 1PUX: S’është kartelë ZIP e vlefshme. + + + Invalid 1PUX file format: Missing export.data + Format i pavlefshëm kartele 1PUX: Mungojnë export.data + + + 1Password Import + Importim 1Password + + + Enter Shortcut + Jepni Shkurtore + + + Action + Veprim + + + Shortcuts + Shkurtore + + + Unknown passkeys error + Gabim i panjohur kyçkalimesh + + + Invalid KDF iterations, cannot decrypt json file + Numër përsëritjesh KDF i pavlefshëm, s’mund të shfshehtëzohet kartelë json + + + Unsupported format, ensure your Bitwarden export is password-protected + Format i pambuluar, sigurohuni se eksportimi juaj Bitwarden është i mbrojtur me fjalëkalim + + + Only PBKDF and Argon2 are supported, cannot decrypt json file + Mbulohen vetëm PBKDF dhe Argon2, s’mund të shfshehtëzohet kartelë json + + + Reset Shortcuts + Riktheji Shkurtoret te Parazgjedhjet + + + Double click an action to change its shortcut + Që t’i ndryshoni shkurtoren, dyklikoni mbi një veprim + + + Filter... + Filtrojini… + + + Shortcut Conflict + Përplasje Shkurtoresh + + + Shortcut %1 conflicts with '%2'. Overwrite shortcut? + Shkurtorja %1 përplaset me “%2”. Të mbishkruhet shkurtorja? + + + Cannot generate valid passphrases because the wordlist is too short + S’prodhohen dot frazëkalime të vlefshëm, ngaqë lista e fjalëve është shumë e shkurtër + + + Encrypted files are not supported. + + + + Proton Pass Import + + + + Delete plugin data? + Të fshihen të dhëna shtojce? + + + Delete plugin data from Entry(s)? + Të fshihen të dhëna shtojce nga Zëri?Të fshihen të dhëna shtojce nga Zërat? + + + Passkey + Kyçkalim + + + Format to use when exporting. Available choices are 'xml', 'csv' or 'html'. Defaults to 'xml'. + + + + start minimized to the system tray + + + + malformed string, possible unescaped delimiter + + + + missing closing delimiter + + + + %1, row: %2, column: %3 + + + + Tags + Etiketa + QtIOCompressor @@ -7930,20 +9258,39 @@ This options is deprecated, use --set-key-file instead. Gabim i brendshëm zlib-i: + + RemoteHandler + + Command `%1` did not finish in time. Process was killed. + Urdhri `%1` s’përfundoi në kohë. Procesi u asgjësua. + + + Failed to upload merged database. Command `%1` did not finish in time. Process was killed. + S’u arrit të ngarkohej bazë të dhënash. Urdhri `%1` s’përfundoi në kohë. Procesi u asgjësua. + + + Invalid download parameters provided. + U dhanë parametra të pavlefshëm shkarkimi. + + + Command `%1` failed to download database. + Urdhri `%1` s’arriti të shkarkojë bazën e të dhënave. + + + Invalid database pointer or upload parameters provided. + U dha shteg naze të dhënash, ose parametra ngarkimi të pavlefshëm. + + + Command `%1` exited with status code: %2 + Urdhri `%1` mbaroi me kod gjendjeje: %2 + + + Failed to upload merged database. Command `%1` exited with status code: %2 + S’u arritën të ngarkohet baza e të dhënave e përzierë. Urdhri `%1` mbaroi me kod gjendjeje: %2 + + ReportsWidgetBrowserStatistics - - Exclude expired entries from the report - - - - Show only entries which have URL set - - - - Show only entries which have browser settings in custom data - - Double-click entries to edit. Që t’i përpunoni, dyklikoni mbi zëra. @@ -7970,19 +9317,19 @@ This options is deprecated, use --set-key-file instead. (Excluded) - (Përjashtuar) + (Përjashtuar) This entry is being excluded from reports - + Ky zë po përjashtohet nga raporte Please wait, browser statistics is being calculated… - + Ju lutemi, prisni, statistikat po llogariten… No entries with a URL, or none has browser extension settings saved. - + S’ka zëra me URL, ose asnjë prej tyre s’ka të ruajtura rregullime zgjerimi shfletuesi. Title @@ -8008,59 +9355,68 @@ This options is deprecated, use --set-key-file instead. Exclude from reports Përjashto nga raporte + + Expire Entry(s)… + + + + Only show entries that have a URL + Shfaq vetëm zëra që kanë një URL + + + Only show entries that have been explicitly allowed or denied + Shfaq vetëm zëra që janë lejuar, ose mohuar shprehimisht + + + Show expired entries + Shfaq zëra të skaduar + + + (Expired) + (Skaduar) + + + Delete plugin data from Entry(s)… + Fshini të dhëna shtojce nga Zëri…Fshini të dhëna shtojce nga Zëra… + ReportsWidgetHealthcheck - Exclude expired entries from the report - + Show expired entries + Shfaq zëra të skaduar - Also show entries that have been excluded from reports - + (Expired) + (Skaduar) Hover over reason to show additional details. Double-click entries to edit. - - - - Bad - Password quality - I keq + Për hollësi shtesë, kalojeni kursorin sipër arsyeje. Për t’i përpunuar, dyklikoni mbi zëra. Bad — password must be changed I keq — fjalëkalimi duhet ndryshuar - - Poor - Password quality - Shumë i dobët - Poor — password should be changed Shumë i dobët — fjalëkalimi duhet ndryshuar - - Weak - Password quality - I dobët - Weak — consider changing the password I dobët — shihni mundësinë e ndryshimit të fjalëkalimit (Excluded) - (Përjashtuar) + (Përjashtuar) This entry is being excluded from reports - + Ky zë po përjashtohet nga raporte Please wait, health data is being calculated… - + Ju lutemi, prisni, të dhënat mbi shëndetin po llogariten… Congratulations, everything is healthy! @@ -8094,12 +9450,20 @@ This options is deprecated, use --set-key-file instead. Exclude from reports Përjashto nga raporte + + Expire Entry(s)… + + + + Show entries that have been excluded from reports + Shfaq zëra që janë përjashtuar nga raporte + ReportsWidgetHibp CAUTION: This report requires sending information to the Have I Been Pwned online service (https://haveibeenpwned.com). If you proceed, your database passwords will be cryptographically hashed and the first five characters of those hashes will be sent securely to this service. Your database remains secure and cannot be reconstituted from this information. However, the number of passwords you send and your IP address will be exposed to this service. - + HAPNI SYTË: Ky raport lyp dërgim informacioni te shërbimi internetor “Have I Been Pwned” (https://haveibeenpwned.com). Nëse vazhdoni, për fjalëkalimet e bazës suaj të të dhënave do të prodhohen hashe kriptografikë dhe pesë shenjat e para të këtyre hasheve do t’i dërgohen në mënyrë të siguruar këtij shërbimi. Baza juaj e të dhënave mbetet e siguruar dhe s’mund të rindërtohet nisur nga ky informacion. Por, numri i fjalëkalimeve që dërgoni dhe adresa juaj IP do t’i ekspozohen këtij shërbimi. Perform Online Analysis @@ -8107,11 +9471,11 @@ This options is deprecated, use --set-key-file instead. Also show entries that have been excluded from reports - + Shfaq gjithashtu zëra që janë përjashtuar nga raporte This build of KeePassXC does not have network functions. Networking is required to check your passwords against Have I Been Pwned databases. - + Ky montim i KeePassXC-së s’ka funksione rrjeti. Punimi në rrjet është i domosdoshëm për të kontrolluar fjalëkalimet tuaj me bazat e të dhënave të shërbimit “I Been Pwned”. Congratulations, no exposed passwords! @@ -8131,11 +9495,11 @@ This options is deprecated, use --set-key-file instead. (Excluded) - (Përjashtuar) + (Përjashtuar) This entry is being excluded from reports - + Ky zë po përjashtohet nga raporte once @@ -8189,12 +9553,83 @@ This options is deprecated, use --set-key-file instead. Exclude from reports Përjashto nga raporte + + Expire Entry(s)… + + + + + ReportsWidgetPasskeys + + Export + Eksporto + + + Import + Importo + + + List of entry URLs + Listë URL-sh zëri + + + Title + Titull + + + Path + Shteg + + + Username + Emër përdoruesi + + + URLs + URL-ra + + + Edit Entry… + Përpunoni Zë… + + + Delete Entry(s)… + Fshini Zë…Fshini Zëra… + + + Relying Party + + + + Show expired entries + Shfaq zëra të skaduar + + + (Expired) + (Skaduar) + + + Export Confirmation + Ripohim Eksportimi + + + The passkey file will be vulnerable to theft and unauthorized use, if left unsecured. Are you sure you want to continue? + Kartela e kyçkalimit do të jetë e cenueshme përballë vjedhjesh dhe përdorimi të paautorizuar. Jeni i sigurt se doni të vazhdohet? + + + Please wait, list of entries with passkeys is being updated… + Ju lutemi, prisni, lista e zërave me kyçkalime po përditësohet… + + + No entries with passkeys. + S’ka zëra me kyçkalime. + ReportsWidgetStatistics Hover over lines with error icons for further information. - + Për informacion të mëtejshëm, kaloni kursorin përsipër rreshta me ikona gabimesh. Name @@ -8206,7 +9641,7 @@ This options is deprecated, use --set-key-file instead. Please wait, database statistics are being calculated… - + Ju lutemi, prisni, statistikat për bazë të dhënash po llogariten… Database name @@ -8226,7 +9661,7 @@ This options is deprecated, use --set-key-file instead. Last saved - + Ruajtur së fundi më Unsaved changes @@ -8242,7 +9677,7 @@ This options is deprecated, use --set-key-file instead. The database was modified, but the changes have not yet been saved to disk. - + Baza e të dhënave qe ndryshuar, por ndryshimet s’janë ruajtur ende në disk. Number of groups @@ -8258,7 +9693,7 @@ This options is deprecated, use --set-key-file instead. The database contains entries that have expired. - + Baza e të dhënave përmban zëra që kanë skaduar. Unique passwords @@ -8270,7 +9705,7 @@ This options is deprecated, use --set-key-file instead. More than 10% of passwords are reused. Use unique passwords when possible. - + Më shumë se 10% e fjalëkalimeve janë ripërdorur. Përdorni fjalëkalime unikë, kur do të mundet. Maximum password reuse @@ -8278,7 +9713,7 @@ This options is deprecated, use --set-key-file instead. Some passwords are used more than three times. Use unique passwords when possible. - + Disa fjalëkalime janë përdorur më shumë se tre herë. Përdorni fjalëkalime unikë, kur do të mundet. Number of short passwords @@ -8294,7 +9729,7 @@ This options is deprecated, use --set-key-file instead. Recommend using long, randomized passwords with a rating of 'good' or 'excellent'. - + Rekomando përdorimin e fjalëkalimeve të gjatë, kuturu, me vlerësim “i mirë”, ose “i shkëlqyer”. Entries excluded from reports @@ -8302,7 +9737,7 @@ This options is deprecated, use --set-key-file instead. Excluding entries from reports, e. g. because they are known to have a poor password, isn't necessarily a problem but you should keep an eye on them. - + Po përjashtohen zëra nga raporte, p.sh., ngaqë dihet se kanë fjalëkalim të dobët, s’është doemos një problem, por duhet t’i vëzhgoni. Average password length @@ -8314,7 +9749,7 @@ This options is deprecated, use --set-key-file instead. Average password length is less than ten characters. Longer passwords provide more security. - + Gjatësia mesatare e fjalëkalimeve është më pak se dhjetë shenja. Fjalëkalimet më të gjatë japin më tepër siguri. @@ -8329,15 +9764,15 @@ This options is deprecated, use --set-key-file instead. No agent running, cannot add identity. - + S’ka agjent në punë, s’shtohet dot identitet. Key identity ownership conflict. Refusing to add. - + Përplasje pronësie identiteti kyçi. S’po pranohet shtim. Agent refused this identity. Possible reasons include: - + Agjenti nuk e pranoi këtë identitet. Në arsyet e mundshme përfshihen: The key has already been added. @@ -8345,22 +9780,30 @@ This options is deprecated, use --set-key-file instead. Restricted lifetime is not supported by the agent (check options). - + Jetëgjatësi e kufizuar nuk mbulohet nga agjenti (shihni mundësitë). A confirmation request is not supported by the agent (check options). - + Një kërkesë ripohimi s’mbulohet nga agjenti (shihni mundësitë). Security keys are not supported by the agent or the security key provider is unavailable. - + Kyçet e sigurisë nuk mbulohen nga agjenti, ose shërbimi i kyçeve të sigurisë s’është i kapshëm. No agent running, cannot remove identity. - + S’ka agjent në punë, s’hiqet dot identitet. No agent running, cannot list identities. + S’ka agjent në punë, s’paraqiten dot identitete. + + + Failed to remove all SSH identities from agent. + + + + All SSH identities removed from agent. @@ -8372,11 +9815,11 @@ This options is deprecated, use --set-key-file instead. Search terms are as follows: [modifiers][field:]["]term["] - + Termat e kërkimit janë si vijon: [ndryshues][fushë:]["]term["] Every search term must match (ie, logical AND) - + Duhet të ketë përkim për krejt termat e kërkimit (d.m.th., DHE logjike) Modifiers @@ -8408,7 +9851,7 @@ This options is deprecated, use --set-key-file instead. match one - + përputhje me një logical OR @@ -8429,6 +9872,10 @@ This options is deprecated, use --set-key-file instead. Search Help Ndihmë Kërkimi + + Save Search + Ruaje Kërkimin + Search (%1)… Search placeholder text, %1 is the keyboard shortcut @@ -8436,16 +9883,12 @@ This options is deprecated, use --set-key-file instead. Case sensitive - + Siç është shkruar Limit search to selected group Kufizoje kërkimin te grupi i përzgjedhur - - Save Search - Ruaje Kërkimin - SettingsClientModel @@ -8489,7 +9932,7 @@ This options is deprecated, use --set-key-file instead. Enable KeepassXC Freedesktop.org Secret Service integration - + Aktivizo integrimin me Shërbimin e Fshehtë KeepassXC të Freedesktop.org General @@ -8497,39 +9940,23 @@ This options is deprecated, use --set-key-file instead. Show notification when passwords are retrieved by clients - + Shfaq njoftim, kur merren fjalëkalime nga klientë <html><head/><body><p>If enabled, any attempt to read a password must be confirmed. Otherwise, clients can read passwords without confirmation when the database is unlocked.</p><p>This option only covers the access to the password of an entry. Clients can always enumerate the items of exposed databases and query their attributes.</p></body></html> - + <html><head/><body><p>Në u aktivizoftë, çdo përpjekje për të lexuar një fjalëkalim duhet ripohuar. Përndryshe, klientë mund të lexojnë fjalëkalime pa u ripohuar, kur baza e të dhënave është e shkyçur.</p><p>Kjo mundësi mbulon vetëm hyrjen te fjalëkalimi i një zëri. Klientët munden përherë t’i numërtojnë objektet e bazave të ekspozuara të të dhënave dhe të bëjnë kërkim te atributet e tyre.</p></body></html> Confirm when passwords are retrieved by clients - - - - <html><head/><body><p><span style=" - font-family:'-apple-system','BlinkMacSystemFont','Segoe UI','Helvetica','Arial','sans-serif','Apple Color - Emoji','Segoe UI Emoji'; font-size:14px; color:#24292e; background-color:#ffffff;">This setting does - not override disabling recycle bin prompts</span></p></body></html> - - + Kërko për ripohim, kur merren fjalëkalime nga klientë Confirm when clients request entry deletion - - - - <html><head/><body><p>This improves compatibility with certain applications - which search for password without unlocking the database first.</p><p>But enabling this may also - crash the client if the database can not be unlocked within a certain timeout. (Usually 25s, but may be a - different value set in applications.)</p></body></html> - - + Kërko për ripohim, kur klientë kërkojnë fshirje zëri Prompt to unlock database before searching - + Shfaq hap shkyçjeje baze të dhënash para kërkimi Exposed database groups: @@ -8549,7 +9976,15 @@ This options is deprecated, use --set-key-file instead. Save current changes to activate the plugin and enable editing of this section. - + Që të aktivizohet shtojca dhe të aktivizohet përpunimi i kësaj pjese, ruani ndryshimet e tanishme. + + + <html><head/><body><p>This setting does not override disabling recycle bin prompts </p></body></html> + <html><head/><body><p>Ky zë s’anashkalon çaktivizim dialogësh koshi riciklimi </p></body></html> + + + <html><head/><body><p>This improves compatibility with certain applications which search for password without unlocking the database first.</p><p>But enabling this may also crash the client if the database can not be unlocked within a certain timeout. (Usually 25s, but may be a different value set in applications.) </p></body></html> + <html><head/><body><p>Kjo përmirëson përputhjen me disa aplikacione të cilët kërkojnë për fjalëkalime pa shkyçur së pari bazën e të dhënave.</p><p>Por aktivizimi i kësaj mund të sjellë vithisjen e klientit, nëse baza e të dhënave s’mund të shkyçet brenda një afati të caktuar mbarimi kohe. (Zakonisht 25s, por mund të jetë vlerë e vendosur ndryshe te aplikacionet.) </p></body></html> @@ -8637,11 +10072,11 @@ This options is deprecated, use --set-key-file instead. Multiple import source path to %1 in %2 - + Shteg burimesh të shumtë importimi te %1 në %2 Conflicting export target path %1 in %2 - + Shteg objektivi eksportimi me përplasje %1 në %2 Export to %1 failed (%2) @@ -8659,20 +10094,20 @@ This options is deprecated, use --set-key-file instead. TagModel - Expired - Ka skaduar - - - Weak Passwords - Fjalëkalim i Dobët + Clear Search + Spastro Kërkimin All Entries Krejt Zërat - Clear Search - Spastro Kërkimin + Expired + Ka skaduar + + + Weak Passwords + Fjalëkalim i Dobët @@ -8691,7 +10126,7 @@ This options is deprecated, use --set-key-file instead. Remove tag "%1" from all entries in this database? - + Të hiqet etiketa “%1” prej krejt zërave te kjo bazë të dhënash? @@ -8702,23 +10137,23 @@ This options is deprecated, use --set-key-file instead. Copy - + Kopjoje Expires in <b>%n</b> second(s) - Skadon pas <b>%n</b> sekonde(ash)Skadon pas <b>%n</b> sekonde(ash) + Skadon pas <b>%n</b> sekondeSkadon pas <b>%n</b> sekondash TotpExportSettingsDialog Copy - + Kopjoje NOTE: These TOTP settings are custom and may not work with other authenticators. TOTP QR code dialog warning - + SHËNIM: Këto rregullime TOTP janë vetjake dhe mund të mos punojnë me mirëfilltësues të tjerë. There was an error creating the QR code. @@ -8778,11 +10213,11 @@ This options is deprecated, use --set-key-file instead. sec Seconds - sek + sek Code size: - Madhësi kodi + Madhësi kodi: digits @@ -8795,7 +10230,8 @@ This options is deprecated, use --set-key-file instead. You have entered an invalid secret key. The key must be in Base32 format. Example: JBSWY3DPEHPK3PXP - + Keni dhënë një kyç të fshehtë të pavlefshëm. Kyçi duhet të jetë në formatin Base32. +Shembull: JBSWY3DPEHPK3PXP Confirm Remove TOTP Settings @@ -8833,11 +10269,11 @@ Example: JBSWY3DPEHPK3PXP An error occurred when trying to retrieve update information, please try again later. - + Ndodhi një gabim, kur provohej të përditësohej informacion, ju lutemi, riprovoni më vonë. <strong>A new version is available.</strong><br/>KeePassXC %1 can be <a href="https://keepassxc.org/download/">downloaded here</a>. - + <strong>Ka të gatshëm një version të ri.</strong><br/>KeePassXC %1 mund të <a href="https://keepassxc.org/download/">shkarkohet këtu</a>. You have the latest version of KeePassXC @@ -8848,27 +10284,7 @@ Example: JBSWY3DPEHPK3PXP WelcomeWidget Start storing your passwords securely in a KeePassXC database - - - - Create new database - Krijoni bazë të re të dhënash - - - Open existing database - Hap bazë ekzistuese të dhënash - - - Import from KeePass 1 - Importo prej Keepass 1 - - - Import from 1Password - Importo prej 1Password - - - Import from CSV - Importo prej CSV + Filloni t’i depozitoni fjalëkalimet tuaj në mënyrë të siguruar te një bazë të dhënash KeePassXC Recent databases @@ -8882,6 +10298,18 @@ Example: JBSWY3DPEHPK3PXP Welcome to KeePassXC %1 Mirë se vini te KeePassXC %1 + + Create Database + Krijo Bazë të Dhënash + + + Open Database + Hap Bazë të Dhënash + + + Import File + Importo Kartelë + WinUtils @@ -8898,53 +10326,22 @@ Example: JBSWY3DPEHPK3PXP S’u regjistrua dot shkurtore globale - - WindowsHello - - Failed to init KeePassXC crypto. - S’u arrit të gatitet kriptografi KeePassXC-je - - - Failed to encrypt key data. - S’u arrit të fshehtësohen të dhëna kyçi. - - - Failed to get Windows Hello credential. - - - - Failed to decrypt key data. - S’u arrit të shfshehtësohen të dhëna kyçi. - - YubiKey - - %1 No interface, slot %2 - - General: Të përgjithshme: Could not find interface for hardware key with serial number %1. Please connect it to continue. - + S’u gjet dot ndërfaqe për kyçin hardware me numrin serial %1. Ju lutemi, që të vazhdohet, lidheni. YubiKeyEditWidget - - Refresh hardware tokens - - - - Refresh - Rifreskoje - Hardware key slot selection - + Përzgjedhje vendi kyçi hardware Could not find any hardware keys! @@ -8952,7 +10349,7 @@ Example: JBSWY3DPEHPK3PXP Selected hardware key slot does not support challenge-response! - + Kanali i përzgjedhur për kyç hardware nuk mbulon sfidë-përgjigje! Challenge-Response @@ -8974,10 +10371,6 @@ Example: JBSWY3DPEHPK3PXP Challenge-Response set, click to change or remove Pyetje-Përgjigje u ujdis, klikoni që ta ndryshoni, ose hiqni - - <p>If you own a <a href="https://www.yubico.com/">YubiKey</a> or <a href="https://onlykey.io">OnlyKey</a>, you can use it for additional security.</p><p>The key requires one of its slots to be programmed as <a href="https://www.yubico.com/products/services-software/challenge-response/">HMAC-SHA1 Challenge-Response</a>.</p> - - Detecting hardware keys… Po pikasen kyçe hardware… @@ -8986,35 +10379,32 @@ Example: JBSWY3DPEHPK3PXP No hardware keys detected S’u pikasën kyçe hardware - - - YubiKeyInterface - %1 Invalid slot specified - %2 + Refresh hardware keys + Rifresko kyçe hardware + + + <p>If you own a <a href="https://www.yubico.com/">YubiKey</a> or <a href="https://onlykey.io">OnlyKey</a>, you can use it for additional security.</p><p>The key requires one of its slots to be programmed with <a href="https://keepassxc.org/docs/#faq-yubikey-howto">Challenge-Response</a>.</p> + <p>Nëse keni një <a href="https://www.yubico.com/">YubiKey</a> ose <a href="https://onlykey.io">OnlyKey</a>, mund ta përdorni për siguri të mëtejshme.</p><p>Kyçi lyp që një nga kanalet e tij të programohet me <a href="https://keepassxc.org/docs/#faq-yubikey-howto">Challenge-Response</a>.</p> + + + Hardware keys found, but no slots are configured YubiKeyInterfacePCSC - - (PCSC) %1 [%2] Challenge-Response - Slot %3 - - The YubiKey PCSC interface has not been initialized. Ndërfaqja PCSC YubiKey s’është gatitur. - - Hardware key is currently in use. - Kyçi hardware është aktualisht në përdorim. - Could not find or access hardware key with serial number %1. Please present it to continue. - + S’u gjet dot, ose s’u përdor dot kyç hardware me numër serial %1. Që të vazhdohet, ju lutemi, silleni. Hardware key is locked or timed out. Unlock or re-present it to continue. - + Kyçi hardware është i kyçur, ose mbaroi koha. Që të vazhdohet, shkyçeni, ose riparaqiteni. Hardware key was not found or is not configured. @@ -9022,27 +10412,34 @@ Example: JBSWY3DPEHPK3PXP Failed to complete a challenge-response, the PCSC error code was: %1 - + S’u arrit të plotësohet një hap sfidë-përgjigje, kodi i gabimit PCSC qe: %1 + + + (NFC) %1 [%2] - Slot %3, %4 + YubiKey display fields + (NFC) %1 [%2] - Kanali %3, %4 + + + Press + USB Challenge-Response Key interaction request + Shtypeni + + + Passive + USB Challenge-Response Key no interaction required + Pasiv YubiKeyInterfaceUSB Unknown - - - - (USB) %1 [%2] Configured Slot - %3 - - - - (USB) %1 [%2] Challenge-Response - Slot %3 - %4 - + E panjohur Press USB Challenge-Response Key interaction request - + Shtypeni Passive @@ -9053,17 +10450,13 @@ Example: JBSWY3DPEHPK3PXP The YubiKey USB interface has not been initialized. Ndërfaqja USB YubiKey s’është gatitur. - - Hardware key is currently in use. - Kyçi hardware është aktualisht në përdorim. - Could not find hardware key with serial number %1. Please plug it in to continue. - + S’u gjet dot kyç hardware me numër serial %1. Që të vazhdohet, ju lutemi, vendoseni. Hardware key timed out waiting for user interaction. - + Kyçit hardware i mbaroi koha në pritje të ndërveprimit nga përdorues. A USB error occurred when accessing the hardware key: %1 @@ -9071,7 +10464,17 @@ Example: JBSWY3DPEHPK3PXP Failed to complete a challenge-response, the specific error was: %1 - + S’u arrit të plotësohet një hap sfidë-përgjigje, kodi specifik qe: %1 + + + %1 [%2] - Slot %3 + YubiKey NEO display fields + %1 [%2] - Vendi %3 + + + %1 [%2] - Slot %3, %4 + YubiKey display fields + %1 [%2] - Vendi %3, %4 \ No newline at end of file diff --git a/share/translations/keepassxc_sr.ts b/share/translations/keepassxc_sr.ts index 76d244ae5..36384a200 100644 --- a/share/translations/keepassxc_sr.ts +++ b/share/translations/keepassxc_sr.ts @@ -217,18 +217,50 @@ You must restart the application to set the new language. Would you like to restart now? Морате поново покренути апликацију да бисте поставили нови језик. Поново покренути сада? - - Reset Settings? - Ресетовати подешавања? - - - Are you sure you want to reset all general and security settings to default? - Да ли сте сигурни да желите да вратите све опште и безбедносне поставке на подразумеване? - Select backup storage directory + + Confirm Reset + + + + Are you sure you want to reset all settings to default? + + + + Import KeePassXC Settings + + + + Failed to import settings from %1, not a valid settings file. + + + + Export KeePassXC Settings + + + + Small + + + + Normal + + + + Medium + + + + Large + + + + Custom + + ApplicationSettingsWidgetGeneral @@ -280,25 +312,6 @@ Include beta releases when checking for updates Укључити бета издања приликом провере ажурирања - - On database unlock, show entries that - - - - have expired - On database unlock, show entries that... - - - - days - On database unlock, show entries that will expire within %1 days - - - - will expire within - On database unlock, show entries that... - - File Management Управљање датотекама @@ -323,22 +336,10 @@ Backup database file before saving Направити резервну копију базе података пре сачувавања - - Backup destination - - - - Specifies the database backup file location. Occurrences of "{DB_FILENAME}" are replaced with the filename of the saved database without extension. {TIME:<format>} is replaced with the backup time, see https://doc.qt.io/qt-5/qdatetime.html#toString. <format> defaults to format string "dd_MM_yyyy_hh-mm-ss". - - {DB_FILENAME}.old.kdbx - - Choose... - - Use alternative saving method (may solve problems with Dropbox, Google Drive, GVFS, etc.) @@ -505,6 +506,71 @@ Remember last typed entry for: + + On database unlock, show entries that will expire within + + + + On database unlock, show entries that will expire within + + + + days + number of days warning for password expiration + + + + Destination format: + + + + <html><head/><body><p><span style=" font-weight:600;">{DB_FILENAME}</span> is replaced with the filename of the saved database without extension</p><p><span style=" font-weight:600;">{TIME:&lt;format&gt;}</span> is replaced with the specified time format (default: dd_MM_yyyy_hh-mm-ss)</p><p>See the User Guide for more details</p></body></html> + + + + Choose folder... + + + + Show confirmation before moving entries to recycle bin + + + + Copy data on double clicking field in entry view + + + + Show toolbar + + + + Show the menu bar by pressing the Alt key + + + + Show menubar + + + + Import settings… + + + + Export settings… + + + + Open browser on double clicking URL field in entry view + + + + Font size: + + + + Font size selection + + ApplicationSettingsWidgetSecurity @@ -570,18 +636,6 @@ Hide passwords in the entry preview panel Сакриј лозинке на табли за преглед уноса - - Hide entry notes by default - Подразумевано сакриј белешке о уносу - - - Move entries to recycle bin without confirmation - Премести ставке у корпу за отпатке без потрвде - - - Enable double click to copy the username/password entry columns - - Privacy Приватност @@ -594,6 +648,18 @@ Hide TOTP in the entry preview panel + + Lock databases when switching user + + + + Lock Options + + + + Hide notes in the entry preview panel + + AutoType @@ -641,19 +707,6 @@ Entry does not have attribute for PICKCHARS: %1 - - Invalid conversion type: %1 - - - - Invalid conversion syntax: %1 - - - - Invalid regular expression syntax %1 -%2 - - Invalid placeholder: %1 @@ -1014,10 +1067,6 @@ Do you want to overwrite the passkey in %1 - %2? General Опште - - Browsers installed as snaps are currently not supported. - Прегледници инсталирани као брзи тренутно нису подржани. - Enable integration for these browsers: Омогућите интеграцију ових прегледача: @@ -1189,18 +1238,6 @@ Do you want to overwrite the passkey in %1 - %2? Custom extension ID ИД прилагођеног додатка - - Due to Snap sandboxing, you must run a script to enable browser integration.<br />You can obtain this script from %1 - Због Snap sandboxing-а, морате покренути скрипт да бисте омогућили интеграцију прегледача.<br />Овај скрипт можете добити од %1 - - - KeePassXC-Browser is needed for the browser integration to work. <br />Download it for %1 and %2 and %3. %4 - KeePassXC-Browser је потребан да би интеграција прегледача функционисала. <br />Преузмите га за %1 и %2 и %3. %4 - - - Please see special instructions for browser extension use below - Молимо погледајте посебна упутства за употребу додатка прегледача у наставку - Executable Files Извршне датотеке @@ -1249,6 +1286,14 @@ Do you want to overwrite the passkey in %1 - %2? Allow using localhost with passkeys + + KeePassXC-Browser is needed for the browser integration to work. <br />Download it for %1 and %2 and %3. + + + + Browsers installed using Snap or Flatpak are not supported with exception to Firefox installed using Snap. + + CloneDialog @@ -1391,6 +1436,19 @@ Do you want to overwrite the passkey in %1 - %2? Imported from CSV file: %1 + + No Title Selected + + + + No title column was selected, entries will be hard to tell apart. +Are you sure you want to import? + + + + Tags + + CsvParserModel @@ -1454,6 +1512,14 @@ Backup database located at %2 Recycle Bin Корпа за отпатке + + Database file read error. + + + + No file path was provided. + + DatabaseOpenDialog @@ -1596,14 +1662,6 @@ To prevent this error from appearing, you must go to "Database Settings / S <p>In addition to a password, you can use a secret file to enhance the security of your database. This file can be generated in your database's security settings.</p><p>This is <strong>not</strong> your *.kdbx database file!</p> - - Click to add a key file. - - - - <a href="#" style="text-decoration: underline">I have a key file</a> - - Use hardware key [Serial: %1] @@ -1636,6 +1694,18 @@ Are you sure you want to continue with this file?. Refresh Hardware Keys + + Click to add a key file. + + + + <a href="#" style="text-decoration: underline">I have a key file</a> + + + + Hardware keys found, but no slots are configured. + + DatabaseSettingWidgetMetaData @@ -1670,6 +1740,22 @@ Are you sure you want to continue with this file?. Maintenance + + KeeShare + KeeShare + + + Secret Service Integration + Интеграција тајног сервиса + + + Remote Sync + + + + Database Settings: %1 + + DatabaseSettingsWidgetBrowser @@ -1841,11 +1927,11 @@ Are you sure you want to continue without a password? Слаба лозинка - You must enter a stronger password to protect your database. + This is a weak password! For better protection of your secrets, you should choose a stronger password. - This is a weak password! For better protection of your secrets, you should choose a stronger password. + The provided password does not meet the minimum quality requirement. @@ -2136,6 +2222,50 @@ removed from the database. Autosave delay since last change checkbox + + Public Database Metadata + + + + Warning: the following settings are not encrypted. + + + + Display name: + + + + Publically visible display name used on the unlock dialog + + + + Database public display name + + + + Display color: + + + + Publically visible color used on the unlock dialog + + + + Database public display color chooser + + + + Clear + Очисти + + + Display icon: + + + + Select Database Icon + + DatabaseSettingsWidgetKeeShare @@ -2231,6 +2361,129 @@ removed from the database. Поље „Опис“ базе података + + DatabaseSettingsWidgetRemote + + Sync Commands + + + + Remove + Уклони + + + Command Settings + + + + Name + Име + + + Save + Сними + + + Download + + + + Command: + + + + Download command field + + + + e.g.: "sftp user@hostname" or "scp user@hostname:DatabaseOnRemote.kdbx {TEMP_DATABASE}" + + + + Input: + + + + Download input field + + + + Upload + + + + Upload command field + + + + e.g.: "sftp user@hostname" or "scp {TEMP_DATABASE} user@hostname:DatabaseOnRemote.kdbx" + + + + Upload input field + + + + Name cannot be empty. + + + + Test + + + + Download command cannot be empty. + + + + Download failed with error: %1 + + + + Download finished, but file %1 could not be found. + + + + Download successful. + + + + Save Remote Settings + + + + You have unsaved changes. Do you want to save them? + + + + e.g.: +get DatabaseOnRemote.kdbx {TEMP_DATABASE} +exit +--- +{TEMP_DATABASE} is used as placeholder to store the database in a temporary location +The command has to exit. In case of `sftp` as last command `exit` has to be sent + + + + + e.g.: +put {TEMP_DATABASE} DatabaseOnRemote.kdbx +exit +--- +{TEMP_DATABASE} is used as placeholder to store the database in a temporary location +The command has to exit. In case of `sftp` as last command `exit` has to be sent + + + + + Timeout: + + + + seconds + секунди + + DatabaseTabWidget @@ -2304,6 +2557,11 @@ This is definitely a bug, please report it to the developers. Database tab name modifier %1 [Блокирано] + + %1 [Temporary] + Database tab name modifier + + DatabaseWidget @@ -2427,26 +2685,6 @@ Save changes? File has changed Датотека је промењена - - The database file has changed. Do you want to load the changes? - Датотека базе података је измењена. Да ли желите да учитате измене? - - - Merge Request - Споји захтев - - - The database file has changed and you have unsaved changes. -Do you want to merge your changes? - Датотека базе података се променила, а ви имате насачуване промене. -Да ли желите да спојите своје промене? - - - Could not open the new database file while attempting to autoreload. -Error: %1 - Није било могуће отворити нову датотеку базе података приликом аутоматског учитавања. -Грешка: %1 - Disable safe saves? Онемогућити сигурна сачувавања? @@ -2498,6 +2736,86 @@ Disable safe saves and try again? Database tab name modifier %1 [Нова база] + + Remote Sync did not contain any download or upload commands. + + + + Remote sync '%1' completed successfully! + + + + Remote sync '%1' failed: %2 + + + + Error while saving database %1: %2 + + + + Downloading... + Преузимање... + + + Uploading... + + + + Syncing... + + + + Remove passkey from entry + + + + Do you want to remove the passkey from this entry? + + + + The database file "%1" was modified externally + + + + Do you want to load the changes? + + + + Reload database + + + + Reloading database… + + + + Reload canceled + + + + Reload successful + + + + Reload pending user action… + + + + The database file "%1" was modified externally.<br>How would you like to proceed?<br><br>Merge all changes<br>Ignore the changes on disk until save<br>Discard unsaved changes + + + + The database file "%1" was modified externally.<br>How would you like to proceed?<br><br>Merge all changes then save<br>Overwrite the changes on disk<br>Discard unsaved changes + + + + Database file overwritten. + + + + Database file on disk cannot be unlocked with current credentials.<br>Enter new credentials and/or present hardware key to continue. + + EditEntryWidget @@ -2549,10 +2867,6 @@ Disable safe saves and try again? n/a / - - (encrypted) - (шифровано) - Select private key Одаберите приватни кључ @@ -2651,6 +2965,10 @@ Would you like to correct it? %n year(s) %n година(е)%n година(е)%n година(е) + + Failed to decrypt SSH key, ensure password is correct. + + EditEntryWidgetAdvanced @@ -2822,18 +3140,10 @@ Would you like to correct it? Skip Auto-Submit for this entry Прескочи аутоматско слање за овај унос - - Only send this setting to the browser for HTTP Auth dialogs. If enabled, normal login forms will not show this entry for selection. - Пошаљи ово подешавање у прегледач само за HTTP Auth дијалоге. Ако је омогућено, уобичајени обрасци за пријаву неће приказивати овај унос за избор. - Use this entry only with HTTP Basic Auth Користите овај унос само уз HTTP Basic Auth - - Do not send this setting to the browser for HTTP Auth dialogs. If enabled, HTTP Auth dialogs will not show this entry for selection. - Не шаљи ову поставку претраживачу за HTTP Auth дијалоге. Ако је омогућено, HTTP Auth дијалози неће приказати овај унос за избор. - Do not use this entry with HTTP Basic Auth Не користите овај унос са HTTP Basic Auth @@ -2858,6 +3168,14 @@ Would you like to correct it? Additional URLs + + Only send this entry to the browser for HTTP Auth dialogs. If enabled, normal login forms will not show this entry for selection. + + + + Do not send this entry to the browser for HTTP Auth dialogs. If enabled, HTTP Auth dialogs will not show this entry for selection. + + EditEntryWidgetHistory @@ -3080,6 +3398,10 @@ Would you like to correct it? seconds секунди + + Clear agent + + EditGroupWidget @@ -3522,6 +3844,23 @@ This may cause the affected plugins to malfunction. %1 - Clone %1 - Клон + + Passkey + + + + Invalid conversion type: %1 + + + + Invalid conversion syntax: %1 + + + + Invalid regular expression syntax %1 +%2 + + EntryAttachments @@ -3530,6 +3869,21 @@ This may cause the affected plugins to malfunction. + + EntryAttachmentsDialog + + Form + Форма + + + File name + + + + File contents... + + + EntryAttachmentsModel @@ -3567,14 +3921,6 @@ This may cause the affected plugins to malfunction. Remove Уклони - - Rename selected attachment - Преименуј одабрни прилог - - - Rename - Преименуј - Open selected attachment Отворити одабрани прилог @@ -3688,6 +4034,18 @@ Error: %1 Would you like to overwrite the existing attachment? + + New + + + + Preview + Преглед + + + Failed to preview an attachment: Attachment not found + + EntryAttributesModel @@ -3886,6 +4244,10 @@ Would you like to overwrite the existing attachment? Background Color + + Group Path + + EntryPreviewWidget @@ -4279,6 +4641,14 @@ You can enable the DuckDuckGo website icon service in the security section of th Url + + Could not load key file. + + + + Could not open remote database. Password or key file may be incorrect. + + ImportWizardPageSelect @@ -4382,6 +4752,44 @@ You can enable the DuckDuckGo website icon service in the security section of th KeePass1 Database + + Proton Pass (.json) + + + + Proton Pass JSON Export + + + + Temporary Database + + + + Command: + + + + e.g.: "sftp user@hostname" or "scp user@hostname:DatabaseOnRemote.kdbx {TEMP_DATABASE}" + + + + Input: + + + + e.g.: +get DatabaseOnRemote.kdbx {TEMP_DATABASE} +exit +--- +{TEMP_DATABASE} is used as placeholder to store the database in a temporary location +The command has to exit. In case of `sftp` as last commend `exit` has to be sent + + + + + Remote Database (.kdbx) + + KMessageWidget @@ -5517,11 +5925,6 @@ This version is not meant for production use. Expect some bugs and minor issues, this version is meant for testing purposes. - - WARNING: Your Qt version may cause KeePassXC to crash with an On-Screen Keyboard. -We recommend you use the AppImage available on our downloads page. - - No Tags @@ -5594,6 +5997,10 @@ We recommend you use the AppImage available on our downloads page. Import Passkey + + Remote S&ync… + + Quit Application @@ -5698,6 +6105,10 @@ We recommend you use the AppImage available on our downloads page. Show Password Generator + + Remove Passkey From Entry + + Perform Auto-Type: {USERNAME} @@ -5842,6 +6253,34 @@ We recommend you use the AppImage available on our downloads page. Toggle Allow Screen Capture + + Show Group Panel + + + + Toggle Show Group Panel + + + + Setup Remote Sync… + + + + Password Generator + Генератор Лозинки + + + E&xpire Entry… + + + + Clear SSH Agent + + + + Clear all identities in ssh-agent + + ManageDatabase @@ -5992,6 +6431,25 @@ We recommend you use the AppImage available on our downloads page. Унесите име за приказ и опциони опис за вашу нову базу података: + + NewEntryAttachmentsDialog + + Attachment name cannot be empty + + + + Attachment with the same name already exists + + + + Save attachment + Сними прилог + + + New entry attachment + + + NixUtils @@ -6179,6 +6637,10 @@ We recommend you use the AppImage available on our downloads page. Unexpected EOF when writing private key Неочекиван крај датотеке приликом уписивања приватног кључа + + (encrypted) + (енкриптовано) + OpenSSHKeyGenDialog @@ -6529,10 +6991,6 @@ The following data is missing: Also choose from: Такође бирати између: - - Excluded characters: "0", "1", "l", "I", "O", "|", "﹒" - Изузети знакови: "0", "1", "l", "I", "O", "|", "﹒" - Exclude look-alike characters Изостави сличне карактере @@ -6557,10 +7015,6 @@ The following data is missing: Word Count: Број Фраза: - - Character Count: - Број карактера: - Word Case: Слово реченица: @@ -6573,10 +7027,6 @@ The following data is missing: Add custom wordlist - - character - карактера - Close Затвори @@ -6682,6 +7132,22 @@ Do you want to overwrite it? Special Characters Посебни карактери + + passwordLength + + + + Characters: %1 + + + + MIXED case + + + + Excluded characters: "0", "1", "l", "I", "O", "|", "﹒", "B", "8", "G", "6" + + PasswordWidget @@ -6749,6 +7215,21 @@ Do you want to overwrite it? + + PreviewEntryAttachmentsDialog + + Preview entry attachment + + + + No preview available + + + + Image format not supported + + + QMessageBox @@ -7426,10 +7907,6 @@ Do you want to overwrite it? Invalid word count %1 Неважеће бројање речи %1 - - The word list is too small (< 1000 items) - Листа речи је премала (<1000 предмета) - Title for the entry. Наслов уноса. @@ -7574,10 +8051,6 @@ Do you want to overwrite it? Exit interactive mode. Изађите из интерактивног режима. - - Format to use when exporting. Available choices are 'xml' or 'csv'. Defaults to 'xml'. - - Exports the content of a database to standard output in the specified format. Извози садржај базе података на стандардни излаз у наведеном формату. @@ -8165,18 +8638,6 @@ Kernel: %3 %4 file empty датотека је празна - - malformed string - неисправна ниска - - - missing closing quote - недостаје завршни наводник - - - %1: (row, col) %2,%3 - %1: (линије, колоне) %2,%3 - AES 256-bit AES 256-бит @@ -8621,11 +9082,87 @@ This option is deprecated, use --set-key-file instead. - Unsupported KDF type, cannot decrypt json file + Unknown passkeys error - Unknown passkeys error + Invalid KDF iterations, cannot decrypt json file + + + + Unsupported format, ensure your Bitwarden export is password-protected + + + + Only PBKDF and Argon2 are supported, cannot decrypt json file + + + + Reset Shortcuts + + + + Double click an action to change its shortcut + + + + Filter... + + + + Shortcut Conflict + + + + Shortcut %1 conflicts with '%2'. Overwrite shortcut? + + + + Cannot generate valid passphrases because the wordlist is too short + + + + Encrypted files are not supported. + + + + Proton Pass Import + + + + Delete plugin data? + Обрисати податке о додатку? + + + Delete plugin data from Entry(s)? + + + + Passkey + + + + Format to use when exporting. Available choices are 'xml', 'csv' or 'html'. Defaults to 'xml'. + + + + start minimized to the system tray + + + + malformed string, possible unescaped delimiter + + + + missing closing delimiter + + + + %1, row: %2, column: %3 + + + + Tags @@ -8663,6 +9200,37 @@ This option is deprecated, use --set-key-file instead. Интерна zlib грешка: + + RemoteHandler + + Command `%1` did not finish in time. Process was killed. + + + + Failed to upload merged database. Command `%1` did not finish in time. Process was killed. + + + + Invalid download parameters provided. + + + + Command `%1` failed to download database. + + + + Invalid database pointer or upload parameters provided. + + + + Command `%1` exited with status code: %2 + + + + Failed to upload merged database. Command `%1` exited with status code: %2 + + + ReportsWidgetBrowserStatistics @@ -8729,6 +9297,10 @@ This option is deprecated, use --set-key-file instead. Exclude from reports Изузети из извештаја + + Expire Entry(s)… + + Only show entries that have a URL @@ -8745,36 +9317,33 @@ This option is deprecated, use --set-key-file instead. (Expired) + + Delete plugin data from Entry(s)… + + ReportsWidgetHealthcheck - Hover over reason to show additional details. Double-click entries to edit. - Пређите преко разлога да бисте приказали додатне детаље. Двапут кликните на уносе за уређивање. + Show expired entries + - Bad - Password quality - Баш лоше + (Expired) + + + + Hover over reason to show additional details. Double-click entries to edit. + Пређите преко разлога да бисте приказали додатне детаље. Двапут кликните на уносе за уређивање. Bad — password must be changed Баш лоше — лозинка мора бити промењена - - Poor - Password quality - Бедан - Poor — password should be changed Лоше — лозинку треба променити - - Weak - Password quality - Слаб - Weak — consider changing the password Слабо — размислите о промени лозинке @@ -8823,18 +9392,14 @@ This option is deprecated, use --set-key-file instead. Exclude from reports Изузети из извештаја - - Show expired entries - + + Expire Entry(s)… + Show entries that have been excluded from reports - - (Expired) - - ReportsWidgetHibp @@ -8930,6 +9495,10 @@ This option is deprecated, use --set-key-file instead. Exclude from reports Изузети из извештаја + + Expire Entry(s)… + + ReportsWidgetPasskeys @@ -9171,6 +9740,14 @@ This option is deprecated, use --set-key-file instead. No agent running, cannot list identities. Ниједан агент није покренут, не може да наведе идентитете. + + Failed to remove all SSH identities from agent. + + + + All SSH identities removed from agent. + + SearchHelpWidget @@ -9456,29 +10033,6 @@ This option is deprecated, use --set-key-file instead. Извоз у %1 - - ShortcutSettingsWidget - - Double click an action to change its shortcut - - - - Shortcut Conflict - - - - Filter... - - - - Shortcut %1 conflicts with '%2'. Overwrite shortcut? - - - - Reset Shortcuts - - - TagModel @@ -9768,11 +10322,15 @@ Example: JBSWY3DPEHPK3PXP Нема хардверских кључева - <p>If you own a <a href="https://www.yubico.com/">YubiKey</a> or <a href="https://onlykey.io">OnlyKey</a>, you can use it for additional security.</p><p>The key requires one of its slots to be programmed as <a href="https://docs.yubico.com/yesdk/users-manual/application-otp/challenge-response.html">HMAC-SHA1 Challenge-Response</a>.</p> + Refresh hardware keys - Refresh hardware keys + <p>If you own a <a href="https://www.yubico.com/">YubiKey</a> or <a href="https://onlykey.io">OnlyKey</a>, you can use it for additional security.</p><p>The key requires one of its slots to be programmed with <a href="https://keepassxc.org/docs/#faq-yubikey-howto">Challenge-Response</a>.</p> + + + + Hardware keys found, but no slots are configured diff --git a/share/translations/keepassxc_sv.ts b/share/translations/keepassxc_sv.ts index f25de0341..341ae3813 100644 --- a/share/translations/keepassxc_sv.ts +++ b/share/translations/keepassxc_sv.ts @@ -217,18 +217,50 @@ You must restart the application to set the new language. Would you like to restart now? Du måste starta om programmet för att tillämpa det nya språket. Vill du starta om nu? - - Reset Settings? - Vill du återställa inställningarna? - - - Are you sure you want to reset all general and security settings to default? - Vill du verkligen återställa alla allmäna och säkerhetsinställningar till standardinställning? - Select backup storage directory Välj lagringsplats för säkerhetskopior + + Confirm Reset + Bekräfta återställning + + + Are you sure you want to reset all settings to default? + Vill du verkligen återställa alla inställningar till standardinställning? + + + Import KeePassXC Settings + Importera KeePassXC-inställningar + + + Failed to import settings from %1, not a valid settings file. + Kunde inte importera inställningar från %1, ingen giltig inställningsfil. + + + Export KeePassXC Settings + Exportera KeePassXC-inställningar + + + Small + Liten + + + Normal + Normal + + + Medium + Medium + + + Large + Stor + + + Custom + Anpassad + ApplicationSettingsWidgetGeneral @@ -280,25 +312,6 @@ Include beta releases when checking for updates Inkludera betaversioner vid sökning efter uppdateringar - - On database unlock, show entries that - Vid databasupplåsning, visa poster som - - - have expired - On database unlock, show entries that... - har upphört att gälla - - - days - On database unlock, show entries that will expire within %1 days - dagar - - - will expire within - On database unlock, show entries that... - löper ut inom - File Management Filhantering @@ -323,22 +336,10 @@ Backup database file before saving Säkerhetskopiera databasfilen innan den sparas - - Backup destination - Säkerhetskopieringsmål - - - Specifies the database backup file location. Occurrences of "{DB_FILENAME}" are replaced with the filename of the saved database without extension. {TIME:<format>} is replaced with the backup time, see https://doc.qt.io/qt-5/qdatetime.html#toString. <format> defaults to format string "dd_MM_yyyy_hh-mm-ss". - Anger platsen för databasens säkerhetskopia. Förekomster av {DB_FILENAME}" ersätts med filnamnet för den sparade databasen utan filtillägg. {TIME:<format>} ersätts med säkerhetskopieringstiden, se https://doc.qt.io/qt-5/qdatetime.html#toString. <format> standard för att formatera strängen "dd_MM_yyyy_hh-mm-ss". - {DB_FILENAME}.old.kdbx {DB_FILENAME}.old.kdbx - - Choose... - Välj... - Use alternative saving method (may solve problems with Dropbox, Google Drive, GVFS, etc.) Använd alternativ lagringsmetod (Kan lösa problem med Dropbox, Google Drive, GVFS, etc.) @@ -505,6 +506,71 @@ Remember last typed entry for: Kom ihåg senast inmatade post för: + + On database unlock, show entries that will expire within + Vid databasupplåsning, visa poster som förfaller inom + + + On database unlock, show entries that will expire within + Vid databasupplåsning, visa poster som förfaller inom + + + days + number of days warning for password expiration + dagar + + + Destination format: + Målformat: + + + <html><head/><body><p><span style=" font-weight:600;">{DB_FILENAME}</span> is replaced with the filename of the saved database without extension</p><p><span style=" font-weight:600;">{TIME:&lt;format&gt;}</span> is replaced with the specified time format (default: dd_MM_yyyy_hh-mm-ss)</p><p>See the User Guide for more details</p></body></html> + <html><head/><body><p><span style=" font-weight:600;">{DB_FILENAME}</span> är ersatt av filnamnet för den sparade database utan filnamnstillägg.</p><p><span style=" font-weight:600;">{TIME:&lt;format&gt;}</span> år ersatt av specificerat tidsformat (standard: dd_MM_yyyy_hh-mm-ss).</p><p>Se användarmanualen för fler detaljer.</p></body></html> + + + Choose folder... + Välj mapp... + + + Show confirmation before moving entries to recycle bin + Visa bekräftelse innan poster flyttas till papperskorgen + + + Copy data on double clicking field in entry view + Kopiera data vid dubbelklick på fält i postvyn + + + Show toolbar + Visa verktygsfält + + + Show the menu bar by pressing the Alt key + Visa menyfältet genom att trycka på Alt-tangenten + + + Show menubar + Visa menyfält + + + Import settings… + Importera inställningar... + + + Export settings… + Exportera inställningar... + + + Open browser on double clicking URL field in entry view + Öppna webbläsare vid dubbelklick på URL i postvyn + + + Font size: + Teckenstorlek: + + + Font size selection + Teckenstorleksval + ApplicationSettingsWidgetSecurity @@ -570,18 +636,6 @@ Hide passwords in the entry preview panel Dölj lösenord i förhandsgranskningsrutan - - Hide entry notes by default - Dölj posters anteckningar som standard - - - Move entries to recycle bin without confirmation - Flytta poster till papperskorgen utan bekräftelse - - - Enable double click to copy the username/password entry columns - Aktivera dubbelklick för att kopiera kolumnerna för användarnamn/lösenord - Privacy Integritet @@ -594,6 +648,18 @@ Hide TOTP in the entry preview panel Dölj TOTP i förhandsgranskningspanelen + + Lock databases when switching user + Lås databaserna vid byte av användare + + + Lock Options + Låsningsalternativ + + + Hide notes in the entry preview panel + Dölj anteckningar posters förhandgranskningspanel + AutoType @@ -641,20 +707,6 @@ Entry does not have attribute for PICKCHARS: %1 Posten har inget attribut för PICKCHARS: %1 - - Invalid conversion type: %1 - Ogiltig konverteringstyp: %1 - - - Invalid conversion syntax: %1 - Ogiltig konverteringssyntax: %1 - - - Invalid regular expression syntax %1 -%2 - Ogiltig regular expression-syntax: %1 -%2 - Invalid placeholder: %1 Ogiltig platshållare: %1 @@ -886,24 +938,25 @@ Välj rätt databas för att spara inloggningsuppgifterna. Add to existing entry - + Lägg till i befintlig post Existing passkey found. Do you want to register a new passkey for: - + Befintlig passnyckel hittad. +Vill du registrera en ny passnyckel för: Select the existing passkey and press Update to replace it. - + Markera den befintliga passnyckeln och tryck "Uppdatera" för att ersätta den. Authenticate passkey credentials for: - + Autentisera passnyckeluppgifter för: Do you want to register a passkey for: - + Vill du registrera passnyckel för: @@ -988,16 +1041,17 @@ Vill du ta bort posten? Register a new passkey to this entry: - + Registrera en ny passnyckel för denna post: KeePassXC - Update passkey - + KeePassXC - Uppdatera Passnyckel Entry already has a passkey. Do you want to overwrite the passkey in %1 - %2? - + Posten har redan en passnyckel. +Vill du skriva över passnyckeln i %1 - %2? Register @@ -1022,10 +1076,6 @@ Do you want to overwrite the passkey in %1 - %2? General Allmänt - - Browsers installed as snaps are currently not supported. - Webbläsare installerade via Snap, stöds för närvarande inte. - Enable integration for these browsers: Aktivera integrering i dessa webbläsare: @@ -1197,18 +1247,6 @@ Do you want to overwrite the passkey in %1 - %2? Custom extension ID Anpassat tilläggs-ID - - Due to Snap sandboxing, you must run a script to enable browser integration.<br />You can obtain this script from %1 - På grund av Snaps sandlådeteknik, måste du köra ett skript för att aktivera webbläsarintegration.<br />Du kan hämta skriptet från %1 - - - KeePassXC-Browser is needed for the browser integration to work. <br />Download it for %1 and %2 and %3. %4 - KeePassXC-Browser behövs för att webbläsarintegrationen ska fungera. <br />Ladda ner det för %1 och %2 och %3. %4 - - - Please see special instructions for browser extension use below - Se specialinstruktioner för webbläsarintegreringens användning nedan - Executable Files Körbara filer @@ -1251,11 +1289,19 @@ Do you want to overwrite the passkey in %1 - %2? Allows using insecure http://localhost with passkeys for testing purposes. - + Tillåter användning av osäker http://localhost med passnycklar för teständamål. Allow using localhost with passkeys - + Tillåt användning av localhost med passnycklar + + + KeePassXC-Browser is needed for the browser integration to work. <br />Download it for %1 and %2 and %3. + KeePassXC-Browser behövs för att webbläsarintegrationen ska fungera. <br />Ladda ner det för %1 och %2 och %3. + + + Browsers installed using Snap or Flatpak are not supported with exception to Firefox installed using Snap. + Webbläsare som är installerade via Snap eller Flatpak stöds inte, med Firefox via Snap som enda undantag. @@ -1399,6 +1445,20 @@ Do you want to overwrite the passkey in %1 - %2? Imported from CSV file: %1 Importerat från CSV-fil: %1 + + No Title Selected + Ingen titel vald + + + No title column was selected, entries will be hard to tell apart. +Are you sure you want to import? + Ingen titelkolumn valdes, Posterna kommer att bli svåra att särskilja. +Vill du verkligen importera? + + + Tags + Taggar + CsvParserModel @@ -1462,6 +1522,14 @@ Säkerhetskopierad databas hittad i %2 Recycle Bin Papperskorg + + Database file read error. + Kunde inte läsa databasfilen. + + + No file path was provided. + Ingen filsökväg angavs. + DatabaseOpenDialog @@ -1611,14 +1679,6 @@ För att förhindra att detta fel uppstår igen, måste du gå till "Databa <p>In addition to a password, you can use a secret file to enhance the security of your database. This file can be generated in your database's security settings.</p><p>This is <strong>not</strong> your *.kdbx database file!</p> <p>Som tillägg till ett lösenord, kan du använda en hemlig fil för att förbättra säkerheten i din databas. En sådan fil kan genereras i databasens säkerhetsinställningar.</p><p>Detta är <strong>inte</strong> din *.kdbx-databasfil!</p> - - Click to add a key file. - Klicka för att lägga till en nyckelfil. - - - <a href="#" style="text-decoration: underline">I have a key file</a> - <a href="#" style="text-decoration: underline">Jag har en nyckelfil</a> - Use hardware key [Serial: %1] Använd hårdvarunyckel [Serienummer: %1] @@ -1655,6 +1715,18 @@ Vill du verkligen fortsätta med den här filen? Refresh Hardware Keys Uppdatera hårdvarunycklar + + Click to add a key file. + Klicka för att lägga till en nyckelfil. + + + <a href="#" style="text-decoration: underline">I have a key file</a> + <a href="#" style="text-decoration: underline">Jag har en nyckelfil</a> + + + Hardware keys found, but no slots are configured. + Hårdvarunycklar hittades, men inga anslutningsplatser är konfigurerade. + DatabaseSettingWidgetMetaData @@ -1689,6 +1761,22 @@ Vill du verkligen fortsätta med den här filen? Maintenance Underhåll + + KeeShare + KeeShare + + + Secret Service Integration + Secret Service-integration + + + Remote Sync + Fjärrsynkronisering + + + Database Settings: %1 + Databasinställningar: %1 + DatabaseSettingsWidgetBrowser @@ -1859,14 +1947,14 @@ Vill du verkligen fortsätta utan lösenord? Weak password Svagt lösenord - - You must enter a stronger password to protect your database. - Du måste ange ett starkare lösenord för att skydda din databas. - This is a weak password! For better protection of your secrets, you should choose a stronger password. Detta är ett svagt lösenord! För att bättre skydda dina hemligheter, bör du välja ett starkare lösenord. + + The provided password does not meet the minimum quality requirement. + Det angivna lösenordet möter inte lägsta kvalitetskrav. + DatabaseSettingsWidgetEncryption @@ -2168,6 +2256,50 @@ tas också bort från databasen. Autosave delay since last change checkbox Kryssruta för fördröjning av automatiskt sparande sedan senaste ändring + + Public Database Metadata + Offentlig databas metadata + + + Warning: the following settings are not encrypted. + Varning! Följande inställningar är inte krypterade. + + + Display name: + Visningsnamn: + + + Publically visible display name used on the unlock dialog + Offentligt synligt visningsnamn i upplåsningsdialogen. + + + Database public display name + Databasens offentliga visningsnamn + + + Display color: + Visningsfärg: + + + Publically visible color used on the unlock dialog + Offentligt synlig visningsfärg i upplåsningsdialogen. + + + Database public display color chooser + Databasens offentliga visningsfärgsväljare + + + Clear + Rensa + + + Display icon: + Visningsikon: + + + Select Database Icon + Välj databasikon + DatabaseSettingsWidgetKeeShare @@ -2263,6 +2395,141 @@ tas också bort från databasen. Databasens beskrivning + + DatabaseSettingsWidgetRemote + + Sync Commands + Synkroniseringskommandon + + + Remove + Ta bort + + + Command Settings + Kommandoinställningar + + + Name + Namn + + + Save + Spara + + + Download + Ladda ner + + + Command: + Kommando: + + + Download command field + Nerladdningskommando + + + e.g.: "sftp user@hostname" or "scp user@hostname:DatabaseOnRemote.kdbx {TEMP_DATABASE}" + t.ex.: "sftp user@hostname" eller "scp user@hostname:DatabaseOnRemote.kdbx {TEMP_DATABASE}" + + + Input: + Indata: + + + Download input field + Nerladdningens indata + + + Upload + Ladda upp + + + Upload command field + Uppladdningskommando + + + e.g.: "sftp user@hostname" or "scp {TEMP_DATABASE} user@hostname:DatabaseOnRemote.kdbx" + t.ex.: "sftp user@hostname" eller "scp {TEMP_DATABASE} user@hostname:DatabaseOnRemote.kdbx" + + + Upload input field + Uppladdningens indata + + + Name cannot be empty. + Namnet kan inte vara tomt + + + Test + Testa + + + Download command cannot be empty. + Nerladdningskommandot kan inte vara tomt. + + + Download failed with error: %1 + Nerladdningen misslyckades med felet: %1 + + + Download finished, but file %1 could not be found. + Nerladdning slutförd, men filen %1 kunde inte hittas. + + + Download successful. + Nerladdning slutförd. + + + Save Remote Settings + Spara fjärrinställningar + + + You have unsaved changes. Do you want to save them? + Du har osparade ändringar. Vill du spara dem? + + + e.g.: +get DatabaseOnRemote.kdbx {TEMP_DATABASE} +exit +--- +{TEMP_DATABASE} is used as placeholder to store the database in a temporary location +The command has to exit. In case of `sftp` as last command `exit` has to be sent + + t.ex.: +get DatabaseOnRemote.kdbx {TEMP_DATABASE} +exit +--- +{TEMP_DATABASE} används som platshållare för att lagra databasen på en tillfällig plats +Kommandot måste avslutas. Om "sftp" är det sista kommandot måste "exit" sändas + + + + e.g.: +put {TEMP_DATABASE} DatabaseOnRemote.kdbx +exit +--- +{TEMP_DATABASE} is used as placeholder to store the database in a temporary location +The command has to exit. In case of `sftp` as last command `exit` has to be sent + + t.ex.: +put {TEMP_DATABASE} DatabaseOnRemote.kdbx +exit +--- +{TEMP_DATABASE} används som platshållare för att lagra databasen på en tillfällig plats +Kommandot måste avslutas. Om "sftp" är det sista kommandot måste "exit" sändas + + + + Timeout: + Tidsgräns: + + + seconds + sekunder + + DatabaseTabWidget @@ -2336,6 +2603,11 @@ Detta är definitivt ett programfel, rapportera det till utvecklarna.Database tab name modifier %1 [Låst] + + %1 [Temporary] + Database tab name modifier + %1 [Temporary] + DatabaseWidget @@ -2459,26 +2731,6 @@ Vill du spara ändringarna? File has changed Filen har ändrats - - The database file has changed. Do you want to load the changes? - Databasfilen har ändrats. Vill du läsa in ändringarna? - - - Merge Request - Slå samman begäran - - - The database file has changed and you have unsaved changes. -Do you want to merge your changes? - Databasfilen har ändrats och du har osparade ändringar. -Vill du slå samman dina ändringar? - - - Could not open the new database file while attempting to autoreload. -Error: %1 - Kunde inte öppna den nya databasen vid försök att läsa in automatisk. -Fel: %1 - Disable safe saves? Vill du inaktivera "Spara säkert"? @@ -2530,6 +2782,86 @@ Vill du inaktivera "Spara säkert" och försöka igen? Database tab name modifier %1 [Ny databas] + + Remote Sync did not contain any download or upload commands. + Fjärrsynkroniseringen innehöll inga ner- eller uppladdningskommandon. + + + Remote sync '%1' completed successfully! + Fjärrsynkronisering "%1" slutförd! + + + Remote sync '%1' failed: %2 + Fjärrsynkronisering "%1" misslyckades: %2 + + + Error while saving database %1: %2 + Fel när databas %1 skulle sparas: %2 + + + Downloading... + Laddar ner... + + + Uploading... + Laddar upp... + + + Syncing... + Synkroniserar... + + + Remove passkey from entry + Ta bort passnyckeln från posten + + + Do you want to remove the passkey from this entry? + Vill du ta bort passnyckeln från den här posten? + + + The database file "%1" was modified externally + Databasfilen "%1" har ändrats externt + + + Do you want to load the changes? + Vill du läsa in ändringarna? + + + Reload database + Uppdatera databasen + + + Reloading database… + Uppdaterar databasen... + + + Reload canceled + Uppdateringen avbröts + + + Reload successful + Uppdatering slutförd + + + Reload pending user action… + Uppdatera väntande åtgärd... + + + The database file "%1" was modified externally.<br>How would you like to proceed?<br><br>Merge all changes<br>Ignore the changes on disk until save<br>Discard unsaved changes + Databasfilen "%1" har ändrats externt.<br>Hur vill du fortsätta?<br><br>Vill du slå samman alla ändringar?<br>Ignorera ändringar på disk tills du sparar?<br>Ignorera ändringar som inte har sparats? + + + The database file "%1" was modified externally.<br>How would you like to proceed?<br><br>Merge all changes then save<br>Overwrite the changes on disk<br>Discard unsaved changes + Databasfilen "%1" har ändrats externt.<br>Hur vill du fortsätta?<br><br>Vill du slå samman alla ändringar och spara?<br>Skriva över ändringar på disk?<br>Skippa osparade ändringar? + + + Database file overwritten. + Databasfilen har skrivits över. + + + Database file on disk cannot be unlocked with current credentials.<br>Enter new credentials and/or present hardware key to continue. + Databasfilen på disk kan inte låsas upp med aktuella inloggningsuppgifter. <br>Ange nya uppgifter och/eller hårdvarunyckel för att fortsätta. + EditEntryWidget @@ -2581,10 +2913,6 @@ Vill du inaktivera "Spara säkert" och försöka igen? n/a n/a - - (encrypted) - (krypterad) - Select private key Välj privat nyckel @@ -2687,6 +3015,10 @@ Vill du korrigera det? %n year(s) %n år%n år + + Failed to decrypt SSH key, ensure password is correct. + Kunde inte avkryptera SSH-nyckel, tillse att lösenordet är korrekt. + EditEntryWidgetAdvanced @@ -2858,18 +3190,10 @@ Vill du korrigera det? Skip Auto-Submit for this entry Undanta autoskriv för den här posten - - Only send this setting to the browser for HTTP Auth dialogs. If enabled, normal login forms will not show this entry for selection. - Skicka bara den här inställningen till webbläsaren för HTTP-autentisering. Vid aktivering visas inte den här posten i normala inloggningsformulär. - Use this entry only with HTTP Basic Auth Använd den här posten endast med HTTP Basic Auth - - Do not send this setting to the browser for HTTP Auth dialogs. If enabled, HTTP Auth dialogs will not show this entry for selection. - Skicka inte den här inställningen till webbläsaren för HTTP-autentisering. Vid aktivering visas inte den här posten för markering. - Do not use this entry with HTTP Basic Auth Använd inte här posten med HTTP Basic Auth @@ -2894,6 +3218,14 @@ Vill du korrigera det? Additional URLs Ytterligare URL:er + + Only send this entry to the browser for HTTP Auth dialogs. If enabled, normal login forms will not show this entry for selection. + Skicka bara den här inställningen till webbläsaren för HTTP-autentisering. Vid aktivering visas inte den här posten i normala inloggningsformulär. + + + Do not send this entry to the browser for HTTP Auth dialogs. If enabled, HTTP Auth dialogs will not show this entry for selection. + Skicka inte denna post till webbläsaren för HTTP-autentisering. Vid aktivering visas inte den här posten för markering. + EditEntryWidgetHistory @@ -3116,6 +3448,10 @@ Vill du korrigera det? seconds sekunder + + Clear agent + Rensa agent + EditGroupWidget @@ -3558,6 +3894,24 @@ Det kan medföra att de berörda tilläggen inte fungerar. %1 - Clone %1 - Klona + + Passkey + Passnyckel + + + Invalid conversion type: %1 + Ogiltig konverteringstyp: %1 + + + Invalid conversion syntax: %1 + Ogiltig konverteringssyntax: %1 + + + Invalid regular expression syntax %1 +%2 + Ogiltig regular expression-syntax: %1 +%2 + EntryAttachments @@ -3566,6 +3920,21 @@ Det kan medföra att de berörda tilläggen inte fungerar. Kan inte öppna filen "%1" + + EntryAttachmentsDialog + + Form + Formulär + + + File name + Filnamn + + + File contents... + Filinnehåll + + EntryAttachmentsModel @@ -3603,14 +3972,6 @@ Det kan medföra att de berörda tilläggen inte fungerar. Remove Ta bort - - Rename selected attachment - Byt namn på markerad bilaga - - - Rename - Byt namn - Open selected attachment Öppna markerad bilaga @@ -3725,6 +4086,18 @@ Would you like to overwrite the existing attachment? Bilagan "%1" finns redan. Vill du skriva över den befintliga bilagan? + + New + Nytt + + + Preview + Förhandsgranska + + + Failed to preview an attachment: Attachment not found + Kunde inte förhandsgranska en bilaga: Bilagan hittades inte + EntryAttributesModel @@ -3923,6 +4296,10 @@ Vill du skriva över den befintliga bilagan? Background Color Bakgrundsfärg + + Group Path + Gruppsökväg + EntryPreviewWidget @@ -4317,6 +4694,14 @@ Du kan aktivera ikontjänsten från DuckDuckGo, i säkerhetssektionen av program Url URL + + Could not load key file. + Kunde inte läsa in nyckelfil. + + + Could not open remote database. Password or key file may be incorrect. + Kunde inte öppna fjärrdatabas. Lösenord eller nyckelfil kan vara felaktig. + ImportWizardPageSelect @@ -4420,6 +4805,50 @@ Du kan aktivera ikontjänsten från DuckDuckGo, i säkerhetssektionen av program KeePass1 Database KeePass 1-databas + + Proton Pass (.json) + Proton Pass (.json) + + + Proton Pass JSON Export + Proton Pass JSON-export + + + Temporary Database + Temporär databas + + + Command: + Kommando: + + + e.g.: "sftp user@hostname" or "scp user@hostname:DatabaseOnRemote.kdbx {TEMP_DATABASE}" + t.ex.: "sftp user@hostname" eller "scp user@hostname:DatabaseOnRemote.kdbx {TEMP_DATABASE}" + + + Input: + Indata: + + + e.g.: +get DatabaseOnRemote.kdbx {TEMP_DATABASE} +exit +--- +{TEMP_DATABASE} is used as placeholder to store the database in a temporary location +The command has to exit. In case of `sftp` as last commend `exit` has to be sent + + t.ex.: +get DatabaseOnRemote.kdbx {TEMP_DATABASE} +exit +--- +{TEMP_DATABASE} används som platshållare för att lagra databasen på en tillfällig plats +Kommandot måste avslutas. Om "sftp" är sista kommentar måste "exit" sändas + + + + Remote Database (.kdbx) + Fjärrdatabas (.kdbx) + KMessageWidget @@ -4511,7 +4940,7 @@ Om detta upprepas, kan din databasfil vara skadad. (HMAC mismatch) - (HMAC matchningsfel) + (HMAC-matchningsfel) Unknown cipher @@ -4565,57 +4994,57 @@ Om detta upprepas, kan din databasfil vara skadad. Invalid variant map entry name length Translation: variant map = data structure for storing meta data - + Ogiltig inmatningsnamnslängd för variantkarta Invalid variant map entry name data Translation: variant map = data structure for storing meta data - + Ogiltig inmatningsnamnsdata för variantkarta Invalid variant map entry value length Translation: variant map = data structure for storing meta data - + Ogiltig inmatningsvärdeslängd för variantkarta Invalid variant map entry value data Translation comment: variant map = data structure for storing meta data - + Ogiltig inmatningsvärdesdata för variantkarta Invalid variant map Bool entry value length Translation: variant map = data structure for storing meta data - + Ogiltig Bool-inmatningsvärdeslängd för variantkarta Invalid variant map Int32 entry value length Translation: variant map = data structure for storing meta data - + Ogiltig Int32-inmatningsvärdeslängd för variantkarta Invalid variant map UInt32 entry value length Translation: variant map = data structure for storing meta data - + Ogiltig UInt32-inmatningsvärdeslängd för variantkarta Invalid variant map Int64 entry value length Translation: variant map = data structure for storing meta data - + Ogiltig Int64-inmatningsvärdeslängd för variantkarta Invalid variant map UInt64 entry value length Translation: variant map = data structure for storing meta data - + Ogiltig UInt64-inmatningsvärdeslängd för variantkarta Invalid variant map entry type Translation: variant map = data structure for storing meta data - + Ogiltig inmatningstyp för variantkarta Invalid variant map field type size Translation: variant map = data structure for storing meta data - + Ogiltig fälttypstorlek för variantkarta @@ -4942,19 +5371,19 @@ Om detta upprepas, kan din databasfil vara skadad. Incorrect group creation time field size - + Felaktig fältstorlek för gruppskapandetid Incorrect group modification time field size - + Felaktig fältstorlek för gruppändringstid Incorrect group access time field size - + Felaktig fältstorlek för gruppåtkomsttid Incorrect group expiry time field size - + Felaktig fältstorlek för grupputgångstid Incorrect group icon field size @@ -4986,7 +5415,7 @@ Om detta upprepas, kan din databasfil vara skadad. Invalid entry UUID field size - + Ogiltig fältstorlek för inmatnings-UUID Invalid entry group id field size @@ -5560,12 +5989,6 @@ Den här versionen är inte avsedd för produktionsanvändning. Expect some bugs and minor issues, this version is meant for testing purposes. Du använder en förhandsversion av KeePassXC. Förvänta dig några fel och mindre problem, den här versionen är avsedd för teständamål. - - - WARNING: Your Qt version may cause KeePassXC to crash with an On-Screen Keyboard. -We recommend you use the AppImage available on our downloads page. - VARNING! Din Qt-version kan orsaka att KeePassXC kraschar med ett skärmtangentbord. -Vi rekommenderar att du använder den AppImage som finns på vår nerladdningssida. No Tags @@ -5639,6 +6062,10 @@ Vi rekommenderar att du använder den AppImage som finns på vår nerladdningssi Import Passkey Importera passnyckel + + Remote S&ync… + Fjärrs&ynkronisering... + Quit Application Avsluta programmet @@ -5743,6 +6170,10 @@ Vi rekommenderar att du använder den AppImage som finns på vår nerladdningssi Show Password Generator Visa lösenordsgenerator + + Remove Passkey From Entry + Ta bort passnyckeln från posten + Perform Auto-Type: {USERNAME} Utför autoskriv: {ANVÄNDARNAMN} @@ -5887,6 +6318,34 @@ Vi rekommenderar att du använder den AppImage som finns på vår nerladdningssi Toggle Allow Screen Capture Tillåt/Neka skärmklipp + + Show Group Panel + Visa gruppanel + + + Toggle Show Group Panel + Visa/Dölj gruppanel + + + Setup Remote Sync… + Ställ in fjärrsynkronisering... + + + Password Generator + Lösenordsgenerator + + + E&xpire Entry… + Post &utgår... + + + Clear SSH Agent + Rensa SSH-agent + + + Clear all identities in ssh-agent + Ta bort alla identiteter i SSH-agenten + ManageDatabase @@ -6037,6 +6496,25 @@ Vi rekommenderar att du använder den AppImage som finns på vår nerladdningssi Fyll i visningsnamnet och en frivillig beskrivning för din nya databas: + + NewEntryAttachmentsDialog + + Attachment name cannot be empty + Bilagans namn kan inte vara tomt + + + Attachment with the same name already exists + Det finns redan en bilaga med samma namn + + + Save attachment + Spara bifogad fil + + + New entry attachment + Ny postbilaga + + NixUtils @@ -6224,6 +6702,10 @@ Vi rekommenderar att du använder den AppImage som finns på vår nerladdningssi Unexpected EOF when writing private key Oväntad EOF, vid skrivning av privat nyckel + + (encrypted) + (krypterad) + OpenSSHKeyGenDialog @@ -6272,7 +6754,7 @@ Vi rekommenderar att du använder den AppImage som finns på vår nerladdningssi Export the following passkey entries. - + Exportera följande passnyckelposter. @@ -6346,15 +6828,15 @@ Vill du skriva över den? Import the following passkey: - + Importera följande passnyckel: Import the following passkey to this entry: - + Importera följande passnyckel till denna post: Default passkeys group (Imported Passkeys) - + Ordinarie passnyckelgrupp (Importerade passnycklar) @@ -6377,25 +6859,27 @@ Vill du skriva över den? Open passkey file - + Öppna passnyckelfil Cannot import passkey - + Kan inte importera passnyckel Cannot import passkey file "%1". Data is missing. - + Kan inte importera passnyckelfil "%1". Data saknas. Cannot import passkey file "%1". The following data is missing: %2 - + Kan inte importera passnyckelfil "%1". +Följande data saknas: +%2 Cannot import passkey file "%1". Private key is missing or malformed. - + Kan inte importera passnyckelfil "%1". Privat nyckel saknas eller är felaktig. @@ -6576,10 +7060,6 @@ The following data is missing: Also choose from: Välj också från: - - Excluded characters: "0", "1", "l", "I", "O", "|", "﹒" - Undanta tecknen: "0", "1", "l", "I", "O", "|", "﹒" - Exclude look-alike characters Undanta tecken som liknar varandra @@ -6604,10 +7084,6 @@ The following data is missing: Word Count: Antal ord: - - Character Count: - Antal tecken: - Word Case: Skiftläge: @@ -6620,10 +7096,6 @@ The following data is missing: Add custom wordlist Lägg till anpassad ordlista - - character - tecken - Close Stäng @@ -6730,6 +7202,22 @@ Vill du skriva över den? Special Characters Specialtecken + + passwordLength + Lösenordslängd + + + Characters: %1 + Tecken: %1 + + + MIXED case + BLANDAT fall + + + Excluded characters: "0", "1", "l", "I", "O", "|", "﹒", "B", "8", "G", "6" + Undantagna tecken: "0", "1", "l", "I", "O", "|", "﹒", "B", "8", "G", "6" + PasswordWidget @@ -6797,6 +7285,21 @@ Vill du skriva över den? Tryck &TAB mellen tecken + + PreviewEntryAttachmentsDialog + + Preview entry attachment + Förhandsgranska postbilaga + + + No preview available + Ingen förhandsgranskning tillgänglig + + + Image format not supported + Bildformatet stöds inte + + QMessageBox @@ -7475,10 +7978,6 @@ Vill du skriva över den? Invalid word count %1 Ogiltigt antal ord %1 - - The word list is too small (< 1000 items) - Ordlistan är för liten (<1000 objekt) - Title for the entry. Titel för posten. @@ -7623,10 +8122,6 @@ Vill du skriva över den? Exit interactive mode. Avsluta interaktivt läge. - - Format to use when exporting. Available choices are 'xml' or 'csv'. Defaults to 'xml'. - Format att använda vid export. Tillgängliga alternativ är "xml" eller "csv". Standardvärdet är "xml". - Exports the content of a database to standard output in the specified format. Exporterar innehållet i en databas till standardutdata i angivet format. @@ -8215,18 +8710,6 @@ Kärna: %3 %4 file empty filen är tom - - malformed string - felaktigt uppbyggd sträng - - - missing closing quote - saknar avslutande citationstecken - - - %1: (row, col) %2,%3 - %1: (rad, kolumn) %2,%3 - AES 256-bit AES 256-bit @@ -8672,12 +9155,88 @@ Det här alternativet är föråldrat, använd --set-key-file istället.Genvägar - Unsupported KDF type, cannot decrypt json file - KDF-typen stöds inte, det går inte att dekryptera json-filen + Unknown passkeys error + Okänt passnyckelfel - Unknown passkeys error - + Invalid KDF iterations, cannot decrypt json file + Ogiltiga KDF-upprepningar, kan inte avkryptera json-filen. + + + Unsupported format, ensure your Bitwarden export is password-protected + Formatet stöds inte, tillse att din Bitwarden-export är lösenordsskyddad. + + + Only PBKDF and Argon2 are supported, cannot decrypt json file + Endast PBKDF och Argon2 stöds, kan inte avkryptera json-filen. + + + Reset Shortcuts + Återställ genvägar + + + Double click an action to change its shortcut + Dubbelklicka på åtgärden för att ändra genväg + + + Filter... + Filter... + + + Shortcut Conflict + Genvägskonflikt + + + Shortcut %1 conflicts with '%2'. Overwrite shortcut? + Genväg %1 står i konflikt med "%2". Vill du skriva över genvägen?? + + + Cannot generate valid passphrases because the wordlist is too short + Kan inte generera giltiga lösenordsfraser för att ordlistan är för kort + + + Encrypted files are not supported. + Krypterade filer stöds inte. + + + Proton Pass Import + Proton Pass-import + + + Delete plugin data? + Vill du ta bort tilläggsdata? + + + Delete plugin data from Entry(s)? + Vill du ta bort insticksdata från post?Vill du ta bort insticksdata från poster? + + + Passkey + Passnyckel + + + Format to use when exporting. Available choices are 'xml', 'csv' or 'html'. Defaults to 'xml'. + Format att använda vid export. Tillgängliga alternativ är "xml", "csv" eller "html". Standardvärdet är "xml". + + + start minimized to the system tray + starta minimerad i systemfältet + + + malformed string, possible unescaped delimiter + felaktig sträng, möjligen ej utkommenterad avgränsare + + + missing closing delimiter + saknar avslutande avgränsare + + + %1, row: %2, column: %3 + %1, rad: %2, kolumn: %3 + + + Tags + Taggar @@ -8714,6 +9273,37 @@ Det här alternativet är föråldrat, använd --set-key-file istället.Internt zlib-fel: + + RemoteHandler + + Command `%1` did not finish in time. Process was killed. + Kommandot "%1" slutfördes inte i tid. Processen dödades. + + + Failed to upload merged database. Command `%1` did not finish in time. Process was killed. + Det gick inte att ladda upp den sammanslagna databasen. Kommandot %1 slutfördes inte i tid. Processen dödades. + + + Invalid download parameters provided. + Ogiltiga nerladdningsparametrar har angetts. + + + Command `%1` failed to download database. + Kunde inte ladda ner databasen med kommandot "%1". + + + Invalid database pointer or upload parameters provided. + Ogiltiga databaspekare eller uppladdningsparametrar har angetts. + + + Command `%1` exited with status code: %2 + Kommandot "%1" avslutades med statuskod: %2 + + + Failed to upload merged database. Command `%1` exited with status code: %2 + Det gick inte att ladda upp den sammanslagna databasen. Kommandot "%1" avslutades med statuskod: %2 + + ReportsWidgetBrowserStatistics @@ -8780,6 +9370,10 @@ Det här alternativet är föråldrat, använd --set-key-file istället.Exclude from reports Undanta från rapporter + + Expire Entry(s)… + Post utgår...Poster utgår... + Only show entries that have a URL Visa endast poster som har en URL @@ -8796,36 +9390,33 @@ Det här alternativet är föråldrat, använd --set-key-file istället. (Expired) (Förfallen) + + Delete plugin data from Entry(s)… + Tar bort insticksdata från post…Tar bort insticksdata från poster… + ReportsWidgetHealthcheck - Hover over reason to show additional details. Double-click entries to edit. - Håll muspekaren över anledning, för att visa fler detaljer. Dubbelklicka på posten för att redigera. + Show expired entries + Visa förfallna poster - Bad - Password quality - Usel + (Expired) + (Förfallen) + + + Hover over reason to show additional details. Double-click entries to edit. + Håll muspekaren över anledning, för att visa fler detaljer. Dubbelklicka på posten för att redigera. Bad — password must be changed Usel — Lösenordet måste ändras - - Poor - Password quality - Dålig - Poor — password should be changed Dålig — Lösenordet måste ändras - - Weak - Password quality - Svag - Weak — consider changing the password Svag — Överväg att ändra lösenordet @@ -8874,18 +9465,14 @@ Det här alternativet är föråldrat, använd --set-key-file istället.Exclude from reports Undanta från rapporter - - Show expired entries - Visa förfallna poster + + Expire Entry(s)… + Post utgår...Poster utgår... Show entries that have been excluded from reports Visa poster som har undantagits från rapporter - - (Expired) - (Förfallen) - ReportsWidgetHibp @@ -8981,6 +9568,10 @@ Det här alternativet är föråldrat, använd --set-key-file istället.Exclude from reports Undanta från rapporter + + Expire Entry(s)… + Post utgår...Poster utgår... + ReportsWidgetPasskeys @@ -9042,11 +9633,11 @@ Det här alternativet är föråldrat, använd --set-key-file istället. Please wait, list of entries with passkeys is being updated… - + Vänta! Listan över poster med passnycklar uppdateras... No entries with passkeys. - + Det finns inga poster med passnycklar. @@ -9222,6 +9813,14 @@ Det här alternativet är föråldrat, använd --set-key-file istället.No agent running, cannot list identities. Tjänsten körs inte, kan inte lista identiteter. + + Failed to remove all SSH identities from agent. + Kunde inte ta bort alla SSH-identiteter från agenten. + + + All SSH identities removed from agent. + Alla SSH-identiteter borttagna från agenten. + SearchHelpWidget @@ -9400,7 +9999,7 @@ Det här alternativet är föråldrat, använd --set-key-file istället. <html><head/><body><p>This improves compatibility with certain applications which search for password without unlocking the database first.</p><p>But enabling this may also crash the client if the database can not be unlocked within a certain timeout. (Usually 25s, but may be a different value set in applications.) </p></body></html> - <html><head/><body><p>Detta förbättrar kompatibiliteten med vissa program som söker efter lösenord utan att först låsa upp databasen.</p></p>Men aktivering av detta kan också få klienten att krascha om databasen inte kan låsas upp inom en viss tidsgräns (Vanligen 25s, men kan vara ett annat värde, angivet i programmet.)</p></body></html> + <html><head/><body><p>Detta förbättrar kompatibiliteten med vissa program som söker efter lösenord utan att först låsa upp databasen.</p><p>Men aktivering av detta kan också få klienten att krascha om databasen inte kan låsas upp inom en viss tidsgräns (Vanligen 25s, men kan vara ett annat värde, angivet i programmet.) </p></body></html> @@ -9507,29 +10106,6 @@ Det här alternativet är föråldrat, använd --set-key-file istället.Exportera till %1 - - ShortcutSettingsWidget - - Double click an action to change its shortcut - Dubbelklicka på åtgärden för att ändra genväg - - - Shortcut Conflict - Genvägskonflikt - - - Filter... - Filter... - - - Shortcut %1 conflicts with '%2'. Overwrite shortcut? - Genväg %1 står i konflikt med "%2". Vill du skriva över genvägen?? - - - Reset Shortcuts - Återställ genvägar - - TagModel @@ -9818,14 +10394,18 @@ Exempel: JBSWY3DPEHPK3PXP No hardware keys detected Inga hårdvarunycklar identifierade - - <p>If you own a <a href="https://www.yubico.com/">YubiKey</a> or <a href="https://onlykey.io">OnlyKey</a>, you can use it for additional security.</p><p>The key requires one of its slots to be programmed as <a href="https://docs.yubico.com/yesdk/users-manual/application-otp/challenge-response.html">HMAC-SHA1 Challenge-Response</a>.</p> - <p>Om du äger en <a href="https://www.yubico.com/">YubiKey</a> eller en <a href="https://onlykey.io">OnlyKey</a>, kan du använda den för ytterligare säkerhet.</p><p>Nyckeln kräver att en av dess anslutningsplatser programmeras som <a href="https://docs.yubico.com/yesdk/users-manual/application-otp/challenge-response.html">HMAC-SHA1 Challenge-Response</a>.</p> - Refresh hardware keys Uppdatera hårdvarunycklar + + <p>If you own a <a href="https://www.yubico.com/">YubiKey</a> or <a href="https://onlykey.io">OnlyKey</a>, you can use it for additional security.</p><p>The key requires one of its slots to be programmed with <a href="https://keepassxc.org/docs/#faq-yubikey-howto">Challenge-Response</a>.</p> + <p>Om du äger en <a href="https://www.yubico.com/">YubiKey</a> eller en <a href="https://onlykey.io">OnlyKey</a>, kan du använda den för ytterligare säkerhet.</p><p>Nyckeln kräver att en av dess anslutningsplatser programmeras som <a href="https://keepassxc.org/docs/#faq-yubikey-howto">Challenge-Response</a>.</p> + + + Hardware keys found, but no slots are configured + Hårdvarunycklar hittades, men inga anslutningsplatser är konfigurerade. + YubiKeyInterfacePCSC diff --git a/share/translations/keepassxc_th.ts b/share/translations/keepassxc_th.ts index 9cb11a93a..9d97be0a9 100644 --- a/share/translations/keepassxc_th.ts +++ b/share/translations/keepassxc_th.ts @@ -217,18 +217,50 @@ You must restart the application to set the new language. Would you like to restart now? คุณจะต้องเริ่มแอปใหม่เพื่อตั้งภาษาใหม่ คุณต้องการจะเริ่มแอปใหม่ตอนนี้หรือไม่? - - Reset Settings? - ล้างการตั้งค่าหรือไม่? - - - Are you sure you want to reset all general and security settings to default? - คุณแน่ใจหรือไม่ว่าต้องการคืนค่าทั่วไปและค่าความปลอดภัยสู่ค่าเริ่มต้น - Select backup storage directory เลือกไดเรกทอรีจัดเก็บข้อมูลสำรอง + + Confirm Reset + ยืนยันการล้างค่า + + + Are you sure you want to reset all settings to default? + คุณแน่ใจหรือไม่ที่จะล้างการตั้งค่าทั้งหมดไปเป็นค่าปริยาย? + + + Import KeePassXC Settings + นำเข้าการตั้งค่า KeePassXC + + + Failed to import settings from %1, not a valid settings file. + + + + Export KeePassXC Settings + ส่งออกการตั้งค่า KeePassXC + + + Small + + + + Normal + + + + Medium + + + + Large + + + + Custom + + ApplicationSettingsWidgetGeneral @@ -280,25 +312,6 @@ Include beta releases when checking for updates ให้ตรวจหารุ่นทดสอบเบตาด้วย ขณะตรวจหาการปรับรุ่น - - On database unlock, show entries that - ในการปลดล็อกฐานข้อมูล ให้แสดงรายการที่ - - - have expired - On database unlock, show entries that... - หมดอายุแล้ว - - - days - On database unlock, show entries that will expire within %1 days - วัน - - - will expire within - On database unlock, show entries that... - จะหมดอายุภายใน - File Management การจัดการแฟ้ม @@ -323,22 +336,10 @@ Backup database file before saving สำรองแฟ้มฐานข้อมูลก่อนการบันทึก - - Backup destination - ปลายทางข้อมูลสํารอง - - - Specifies the database backup file location. Occurrences of "{DB_FILENAME}" are replaced with the filename of the saved database without extension. {TIME:<format>} is replaced with the backup time, see https://doc.qt.io/qt-5/qdatetime.html#toString. <format> defaults to format string "dd_MM_yyyy_hh-mm-ss". - ระบุตำแหน่งแฟ้มฐานข้อมูลสำรอง รายการที่แสดงเป็น "{DB_FILENAME}" จะถูกแทนด้วยชื่อแฟ้มของฐานข้อมูลที่บันทึกไว้โดยไม่มีส่วนขยาย {TIME:<format>} จะถูกแทนด้วยเวลาที่ทำการสำรอง โปรดดู https://doc.qt.io/qt-5/qdatetime.html#toString <format> ค่าปริยายในการจัดรูปแบบสตริง "dd_MM_yyyy_hh-mm-ss" - {DB_FILENAME}.old.kdbx {DB_FILENAME}.old.kdbx - - Choose... - เลือก... - Use alternative saving method (may solve problems with Dropbox, Google Drive, GVFS, etc.) ใช้วิธีการบันทึกแบบอื่น (อาจแก้ปัญหากับ Dropbox, Google Drive, GVFS เป็นต้น) @@ -505,6 +506,71 @@ Remember last typed entry for: จำรายการที่พิมพ์ล่าสุดสำหรับ: + + On database unlock, show entries that will expire within + + + + On database unlock, show entries that will expire within + + + + days + number of days warning for password expiration + วัน + + + Destination format: + รูปแบบปลายทาง: + + + <html><head/><body><p><span style=" font-weight:600;">{DB_FILENAME}</span> is replaced with the filename of the saved database without extension</p><p><span style=" font-weight:600;">{TIME:&lt;format&gt;}</span> is replaced with the specified time format (default: dd_MM_yyyy_hh-mm-ss)</p><p>See the User Guide for more details</p></body></html> + + + + Choose folder... + เลือกโฟลเดอร์... + + + Show confirmation before moving entries to recycle bin + + + + Copy data on double clicking field in entry view + + + + Show toolbar + แสดงแถบเครื่องมือ + + + Show the menu bar by pressing the Alt key + + + + Show menubar + + + + Import settings… + นำเข้าการตั้งค่า... + + + Export settings… + ส่งออกการตั้งค่า... + + + Open browser on double clicking URL field in entry view + + + + Font size: + + + + Font size selection + + ApplicationSettingsWidgetSecurity @@ -570,18 +636,6 @@ Hide passwords in the entry preview panel ซ่อนรหัสผ่านในแผงแสดงตัวอย่างรายการ - - Hide entry notes by default - ซ่อนบันทึกรายการเป็นค่าตั้งต้น - - - Move entries to recycle bin without confirmation - ย้ายรายการไปยังถังขยะโดยไม่ต้องยืนยัน - - - Enable double click to copy the username/password entry columns - เปิดใช้งานดับเบิลคลิกเพื่อคัดลอกคอลัมน์ชื่อผู้ใช้/รหัสผ่าน - Privacy ความเป็นส่วนตัว @@ -594,6 +648,18 @@ Hide TOTP in the entry preview panel + + Lock databases when switching user + + + + Lock Options + + + + Hide notes in the entry preview panel + + AutoType @@ -641,20 +707,6 @@ Entry does not have attribute for PICKCHARS: %1 รายการไม่มีแอตทริบิวต์สำหรับ PICKCHARS: %1 - - Invalid conversion type: %1 - ประเภทคอนเวอร์ชันไม่ถูกต้อง: %1 - - - Invalid conversion syntax: %1 - ลักษณะคอนเวอร์ชันไม่ถูกต้อง: %1 - - - Invalid regular expression syntax %1 -%2 - ลักษณะการถ่ายทอดทั่วไปไม่ถูกต้อง %1 -%2 - Invalid placeholder: %1 ข้อความตัวอย่างไม่ถูกต้อง: 1% @@ -828,7 +880,7 @@ Ctrl + 4 - ใช้แป้นพิมพ์เสมือน (Windows เ Undo - + เลิกทำ @@ -848,7 +900,7 @@ Please select the correct database for saving credentials. KeePassXC - Select Database - + KeePassXC - เลือกฐานข้อมูล @@ -859,7 +911,7 @@ Please select the correct database for saving credentials. Update - + ปรับปรุง Authenticate @@ -867,15 +919,15 @@ Please select the correct database for saving credentials. Register new - + ลงทะเบียนใหม่ Register - + ลงทะเบียน Timeout in <b>%n</b> seconds... - + หมดเวลาใน <b>%n</b> วินาที... Relying Party: %1 @@ -883,7 +935,7 @@ Please select the correct database for saving credentials. Username: %1 - + ชื่อผู้ใช้: %1 KeePassXC - Passkey credentials @@ -960,7 +1012,7 @@ Do you want to delete the entry? KeePassXC - Create a new group - + KeePassXC - สร้างกลุ่มใหม่ Disable @@ -1005,7 +1057,7 @@ Do you want to overwrite the passkey in %1 - %2? Register - + ลงทะเบียน @@ -1026,10 +1078,6 @@ Do you want to overwrite the passkey in %1 - %2? General ทั่วไป - - Browsers installed as snaps are currently not supported. - ยังไม่รองรับเบราว์เซอร์ที่ถูกติดตั้งจาก Snap - Enable integration for these browsers: เปิดการใช้เบราว์เซอร์เหล่านี้ร่วมกับ @@ -1201,18 +1249,6 @@ Do you want to overwrite the passkey in %1 - %2? Custom extension ID รหัสส่วนขยายที่กำหนดเอง - - Due to Snap sandboxing, you must run a script to enable browser integration.<br />You can obtain this script from %1 - เนื่องจาก Snap sandbox คุณต้องเรียกใช้สคริปต์เพื่อเปิดใช้งานการรวมเบราว์เซอร์ <br /> คุณสามารถรับสคริปต์นี้จาก %1 - - - KeePassXC-Browser is needed for the browser integration to work. <br />Download it for %1 and %2 and %3. %4 - จำเป็นต้องมีโปรแกรม KeePassXC-Browser เพื่อให้การผสานกับเบราว์เซอร์ทำงานได้ <br />ดาวน์โหลดมันสำหรับ %1 และ %2 และ %3 %4 - - - Please see special instructions for browser extension use below - โปรดดูคำแนะนำพิเศษสำหรับการใช้งานส่วนขยายเบราว์เซอร์ด้านล่าง - Executable Files แฟ้มปฏิบัติการ @@ -1261,6 +1297,14 @@ Do you want to overwrite the passkey in %1 - %2? Allow using localhost with passkeys + + KeePassXC-Browser is needed for the browser integration to work. <br />Download it for %1 and %2 and %3. + + + + Browsers installed using Snap or Flatpak are not supported with exception to Firefox installed using Snap. + + CloneDialog @@ -1403,6 +1447,19 @@ Do you want to overwrite the passkey in %1 - %2? Imported from CSV file: %1 + + No Title Selected + + + + No title column was selected, entries will be hard to tell apart. +Are you sure you want to import? + + + + Tags + แท็ก + CsvParserModel @@ -1466,6 +1523,14 @@ Backup database located at %2 Recycle Bin ถังขยะ + + Database file read error. + + + + No file path was provided. + + DatabaseOpenDialog @@ -1609,27 +1674,19 @@ To prevent this error from appearing, you must go to "Database Settings / S Select Key File: - + เลือกแฟ้มกุญแจ: <p>In addition to a password, you can use a secret file to enhance the security of your database. This file can be generated in your database's security settings.</p><p>This is <strong>not</strong> your *.kdbx database file!</p> - - Click to add a key file. - - - - <a href="#" style="text-decoration: underline">I have a key file</a> - - Use hardware key [Serial: %1] Use hardware key - + ใช้กุญแจฮาร์ดแวร์ Your database file is NOT a key file! @@ -1655,6 +1712,18 @@ Are you sure you want to continue with this file?. Refresh Hardware Keys + + Click to add a key file. + คลิกเพื่อเพิ่มแฟ้มกุญแจ + + + <a href="#" style="text-decoration: underline">I have a key file</a> + <a href="#" style="text-decoration: underline">ฉันมีแฟ้มกุญแจ</a> + + + Hardware keys found, but no slots are configured. + + DatabaseSettingWidgetMetaData @@ -1689,6 +1758,22 @@ Are you sure you want to continue with this file?. Maintenance ซ่อมบำรุง + + KeeShare + KeeShare + + + Secret Service Integration + การผสานรวมบริการลับ + + + Remote Sync + + + + Database Settings: %1 + + DatabaseSettingsWidgetBrowser @@ -1802,7 +1887,7 @@ This is only necessary if your database is a copy of another and the browser ext No keys found - + ไม่พบกุญแจ Removed keys from database @@ -1860,11 +1945,11 @@ Are you sure you want to continue without a password? รหัสผ่านอ่อนแอ - You must enter a stronger password to protect your database. + This is a weak password! For better protection of your secrets, you should choose a stronger password. - This is a weak password! For better protection of your secrets, you should choose a stronger password. + The provided password does not meet the minimum quality requirement. @@ -2010,7 +2095,7 @@ If you keep this number, your database will not be protected from brute force at Basic - + พื้นฐาน Advanced @@ -2165,6 +2250,50 @@ removed from the database. Autosave delay since last change checkbox + + Public Database Metadata + + + + Warning: the following settings are not encrypted. + + + + Display name: + ชื่อแสดง: + + + Publically visible display name used on the unlock dialog + + + + Database public display name + + + + Display color: + + + + Publically visible color used on the unlock dialog + + + + Database public display color chooser + + + + Clear + ล้าง + + + Display icon: + ไอคอนแสดง: + + + Select Database Icon + เลือกไอคอนฐานข้อมูล + DatabaseSettingsWidgetKeeShare @@ -2260,6 +2389,129 @@ removed from the database. ช่องคำอธิบายฐานข้อมูล + + DatabaseSettingsWidgetRemote + + Sync Commands + + + + Remove + ลบออก + + + Command Settings + + + + Name + ชื่อ + + + Save + บันทึก + + + Download + + + + Command: + + + + Download command field + + + + e.g.: "sftp user@hostname" or "scp user@hostname:DatabaseOnRemote.kdbx {TEMP_DATABASE}" + + + + Input: + + + + Download input field + + + + Upload + + + + Upload command field + + + + e.g.: "sftp user@hostname" or "scp {TEMP_DATABASE} user@hostname:DatabaseOnRemote.kdbx" + + + + Upload input field + + + + Name cannot be empty. + + + + Test + + + + Download command cannot be empty. + + + + Download failed with error: %1 + + + + Download finished, but file %1 could not be found. + + + + Download successful. + + + + Save Remote Settings + + + + You have unsaved changes. Do you want to save them? + + + + e.g.: +get DatabaseOnRemote.kdbx {TEMP_DATABASE} +exit +--- +{TEMP_DATABASE} is used as placeholder to store the database in a temporary location +The command has to exit. In case of `sftp` as last command `exit` has to be sent + + + + + e.g.: +put {TEMP_DATABASE} DatabaseOnRemote.kdbx +exit +--- +{TEMP_DATABASE} is used as placeholder to store the database in a temporary location +The command has to exit. In case of `sftp` as last command `exit` has to be sent + + + + + Timeout: + + + + seconds + วินาที + + DatabaseTabWidget @@ -2333,6 +2585,11 @@ This is definitely a bug, please report it to the developers. Database tab name modifier %1 [ถูกล็อก] + + %1 [Temporary] + Database tab name modifier + + DatabaseWidget @@ -2456,26 +2713,6 @@ Save changes? File has changed แฟ้มเปลี่ยนไปแล้ว - - The database file has changed. Do you want to load the changes? - แฟ้มฐานข้อมูลเปลี่ยนไปแล้ว คุณต้องการโหลดการเปลี่ยนแปลงหรือไม่? - - - Merge Request - คำร้องเพื่อผสาน - - - The database file has changed and you have unsaved changes. -Do you want to merge your changes? - แฟ้มฐานข้อมูลเปลี่ยนไปแล้ว และคุณมีการเปลี่ยนแปลงที่ยังไม่ได้บันทึก -คุณต้องการผสานการเปลี่ยนแปลงของคุณหรือไม่? - - - Could not open the new database file while attempting to autoreload. -Error: %1 - ไม่สามารถเปิดแฟ้มฐานข้อมูลใหม่ขณะพยายามโหลดใหม่โดยอัตโนมัติ -ข้อผิดพลาด: %1 - Disable safe saves? ปิดการบันทึกแบบปลอดภัยหรือไม่ @@ -2527,6 +2764,86 @@ Disable safe saves and try again? Database tab name modifier %1 [ฐานข้อมูลใหม่] + + Remote Sync did not contain any download or upload commands. + + + + Remote sync '%1' completed successfully! + + + + Remote sync '%1' failed: %2 + + + + Error while saving database %1: %2 + + + + Downloading... + กำลังดาวน์โหลด... + + + Uploading... + + + + Syncing... + + + + Remove passkey from entry + + + + Do you want to remove the passkey from this entry? + + + + The database file "%1" was modified externally + + + + Do you want to load the changes? + + + + Reload database + + + + Reloading database… + + + + Reload canceled + + + + Reload successful + + + + Reload pending user action… + + + + The database file "%1" was modified externally.<br>How would you like to proceed?<br><br>Merge all changes<br>Ignore the changes on disk until save<br>Discard unsaved changes + + + + The database file "%1" was modified externally.<br>How would you like to proceed?<br><br>Merge all changes then save<br>Overwrite the changes on disk<br>Discard unsaved changes + + + + Database file overwritten. + + + + Database file on disk cannot be unlocked with current credentials.<br>Enter new credentials and/or present hardware key to continue. + + EditEntryWidget @@ -2578,10 +2895,6 @@ Disable safe saves and try again? n/a n/a - - (encrypted) - (เข้ารหัสลับอยู่) - Select private key เลือกกุญแจส่วนตัว @@ -2684,6 +2997,10 @@ Would you like to correct it? %n year(s) %n ปี + + Failed to decrypt SSH key, ensure password is correct. + + EditEntryWidgetAdvanced @@ -2855,18 +3172,10 @@ Would you like to correct it? Skip Auto-Submit for this entry ข้ามการส่งอัตโนมัติสำหรับรายการนี้ - - Only send this setting to the browser for HTTP Auth dialogs. If enabled, normal login forms will not show this entry for selection. - ส่งการตั้งค่านี้ไปยังเบราว์เซอร์สำหรับกล่องโต้ตอบ HTTP Auth เท่านั้น หากเปิดใช้งาน แบบฟอร์มการเข้าสู่ระบบปกติจะไม่แสดงรายการนี้สำหรับการเลือก - Use this entry only with HTTP Basic Auth ใช้รายการกับ HTTP Basic Auth เท่านั้น: - - Do not send this setting to the browser for HTTP Auth dialogs. If enabled, HTTP Auth dialogs will not show this entry for selection. - อย่าส่งการตั้งค่านี้ไปยังเบราว์เซอร์สำหรับกล่องโต้ตอบ HTTP Auth หากเปิดใช้งาน กล่องโต้ตอบ HTTP Auth จะไม่แสดงรายการนี้สำหรับการเลือก - Do not use this entry with HTTP Basic Auth อย่าใช้รายการนี้กับ HTTP Basic Auth @@ -2889,6 +3198,14 @@ Would you like to correct it? Additional URLs + URL เพิ่มเติม + + + Only send this entry to the browser for HTTP Auth dialogs. If enabled, normal login forms will not show this entry for selection. + + + + Do not send this entry to the browser for HTTP Auth dialogs. If enabled, HTTP Auth dialogs will not show this entry for selection. @@ -3113,6 +3430,10 @@ Would you like to correct it? seconds วินาที + + Clear agent + + EditGroupWidget @@ -3555,6 +3876,24 @@ This may cause the affected plugins to malfunction. %1 - Clone %1 - Clone + + Passkey + + + + Invalid conversion type: %1 + ประเภทคอนเวอร์ชันไม่ถูกต้อง: %1 + + + Invalid conversion syntax: %1 + ลักษณะคอนเวอร์ชันไม่ถูกต้อง: %1 + + + Invalid regular expression syntax %1 +%2 + ลักษณะการถ่ายทอดทั่วไปไม่ถูกต้อง %1 +%2 + EntryAttachments @@ -3563,6 +3902,21 @@ This may cause the affected plugins to malfunction. เปิดแฟ้ม "%1" ไม่ได้ + + EntryAttachmentsDialog + + Form + จาก + + + File name + + + + File contents... + + + EntryAttachmentsModel @@ -3600,14 +3954,6 @@ This may cause the affected plugins to malfunction. Remove ลบออก - - Rename selected attachment - เปลี่ยนชื่อเอกสารแนบที่เลือก - - - Rename - เปลี่ยนชื่อ - Open selected attachment เปิดแฟ้มแนบที่เลือก @@ -3722,6 +4068,18 @@ Would you like to overwrite the existing attachment? มีเอกสารแนบ "%1" อยู่แล้ว คุณต้องการเขียนทับไฟล์แนบที่มีอยู่หรือไม่ + + New + + + + Preview + ดูตัวอย่าง + + + Failed to preview an attachment: Attachment not found + + EntryAttributesModel @@ -3920,6 +4278,10 @@ Would you like to overwrite the existing attachment? Background Color + + Group Path + + EntryPreviewWidget @@ -4312,6 +4674,14 @@ You can enable the DuckDuckGo website icon service in the security section of th Url + URL + + + Could not load key file. + + + + Could not open remote database. Password or key file may be incorrect. @@ -4339,7 +4709,7 @@ You can enable the DuckDuckGo website icon service in the security section of th Import Into: - + ส่งออกไปยัง: New Database @@ -4355,7 +4725,7 @@ You can enable the DuckDuckGo website icon service in the security section of th Import File: - + นำเข้าแฟ้ม: Comma Separated Values (.csv) @@ -4367,11 +4737,11 @@ You can enable the DuckDuckGo website icon service in the security section of th 1Password Vault (.opvault) - + 1Password Vault (.opvault) Bitwarden (.json) - + Bitwarden (.json) KeePass 1 Database (.kdb) @@ -4417,6 +4787,44 @@ You can enable the DuckDuckGo website icon service in the security section of th KeePass1 Database + + Proton Pass (.json) + + + + Proton Pass JSON Export + + + + Temporary Database + + + + Command: + + + + e.g.: "sftp user@hostname" or "scp user@hostname:DatabaseOnRemote.kdbx {TEMP_DATABASE}" + + + + Input: + + + + e.g.: +get DatabaseOnRemote.kdbx {TEMP_DATABASE} +exit +--- +{TEMP_DATABASE} is used as placeholder to store the database in a temporary location +The command has to exit. In case of `sftp` as last commend `exit` has to be sent + + + + + Remote Database (.kdbx) + + KMessageWidget @@ -5557,12 +5965,6 @@ This version is not meant for production use. Expect some bugs and minor issues, this version is meant for testing purposes. หมายเหตุ: คุณกำลังใช้ KeePassXC รุ่นก่อนเผยแพร่ คาดว่าจะมีจุดบกพร่องและปัญหาเล็กน้อย เวอร์ชันนี้มีไว้เพื่อวัตถุประสงค์ในการทดสอบ - - - WARNING: Your Qt version may cause KeePassXC to crash with an On-Screen Keyboard. -We recommend you use the AppImage available on our downloads page. - คำเตือน: เวอร์ชัน Qt ของคุณอาจทำให้ KeePassXC หยุดทำงานด้วยแป้นพิมพ์บนหน้าจอ -เราขอแนะนำให้คุณใช้ AppImage ที่มีอยู่ในหน้าดาวน์โหลดของเรา No Tags @@ -5626,7 +6028,7 @@ We recommend you use the AppImage available on our downloads page. Import… - + นำเข้า... Passkeys… @@ -5636,6 +6038,10 @@ We recommend you use the AppImage available on our downloads page. Import Passkey + + Remote S&ync… + + Quit Application @@ -5646,11 +6052,11 @@ We recommend you use the AppImage available on our downloads page. Open Database - + เปิดฐานข้อมูล Create Database - + สร้างฐานข้อมูล Merge From Database @@ -5740,6 +6146,10 @@ We recommend you use the AppImage available on our downloads page. Show Password Generator + + Remove Passkey From Entry + + Perform Auto-Type: {USERNAME} @@ -5884,6 +6294,34 @@ We recommend you use the AppImage available on our downloads page. Toggle Allow Screen Capture + + Show Group Panel + + + + Toggle Show Group Panel + + + + Setup Remote Sync… + + + + Password Generator + ตัวสร้างรหัสผ่าน + + + E&xpire Entry… + + + + Clear SSH Agent + + + + Clear all identities in ssh-agent + + ManageDatabase @@ -6034,6 +6472,25 @@ We recommend you use the AppImage available on our downloads page. กรุณากรอกชื่อที่แสดง และคำอธิบายเพิ่มเติมสำหรับ ฐานข้อมูล ใหม่ของคุณ + + NewEntryAttachmentsDialog + + Attachment name cannot be empty + + + + Attachment with the same name already exists + + + + Save attachment + + + + New entry attachment + + + NixUtils @@ -6221,6 +6678,10 @@ We recommend you use the AppImage available on our downloads page. Unexpected EOF when writing private key เกิด EOF ที่ไม่คาดคิดขณะเขียนกุญแจส่วนตัว + + (encrypted) + (เข้ารหัสลับอยู่) + OpenSSHKeyGenDialog @@ -6305,7 +6766,7 @@ Do you want to overwrite it? Username: %1 - + ชื่อผู้ใช้: %1 Group @@ -6313,7 +6774,7 @@ Do you want to overwrite it? Database - + ฐานข้อมูล Import Passkey @@ -6572,10 +7033,6 @@ The following data is missing: Also choose from: เลือกจาก: - - Excluded characters: "0", "1", "l", "I", "O", "|", "﹒" - อักขระที่ยกเว้น: "0", "1", "l", "I", "O", "|", "﹒" - Exclude look-alike characters ไม่ใช้อักขระที่หน้าตาคล้ายกัน @@ -6600,10 +7057,6 @@ The following data is missing: Word Count: จำนวนคำ: - - Character Count: - จำนวนตัวอักษร - Word Case: กรณีคำศัพท์: @@ -6616,10 +7069,6 @@ The following data is missing: Add custom wordlist เพิ่มรายการคําที่กําหนดเอง - - character - ตัวอักษร - Close ปิด @@ -6726,6 +7175,22 @@ Do you want to overwrite it? Special Characters อักขระพิเศษ + + passwordLength + + + + Characters: %1 + ตัวอักขระ: %1 + + + MIXED case + + + + Excluded characters: "0", "1", "l", "I", "O", "|", "﹒", "B", "8", "G", "6" + + PasswordWidget @@ -6793,6 +7258,21 @@ Do you want to overwrite it? กด &Tab ระหว่างอักขระ + + PreviewEntryAttachmentsDialog + + Preview entry attachment + + + + No preview available + + + + Image format not supported + + + QMessageBox @@ -7471,10 +7951,6 @@ Do you want to overwrite it? Invalid word count %1 จำนวนคำไม่ถูกรูปแบบ %1 - - The word list is too small (< 1000 items) - รายการคำศัพท์น้อยเกินไป (< 1,000 รายการ) - Title for the entry. หัวเรื่องสำหรับรายการ @@ -7619,10 +8095,6 @@ Do you want to overwrite it? Exit interactive mode. ออกจากโหมดโต้ตอบ - - Format to use when exporting. Available choices are 'xml' or 'csv'. Defaults to 'xml'. - รูปแบบที่จะใช้เมื่อส่งออก ตัวเลือกที่ใช้ได้คือ 'xml' หรือ 'csv' ค่าเริ่มต้นคือ 'xml' - Exports the content of a database to standard output in the specified format. ส่งออกเนื้อหาของฐานข้อมูลไปยังเอาต์พุตมาตรฐานในรูปแบบที่ระบุ @@ -8211,18 +8683,6 @@ Kernel: %3 %4 file empty แฟ้มว่างเปล่า - - malformed string - รูปแบบสตริงไม่ถูกต้อง - - - missing closing quote - เครื่องหมายปิดคำพูดหายไป - - - %1: (row, col) %2,%3 - %1: (row, col) %2,%3 - AES 256-bit AES 256 บิต @@ -8591,11 +9051,11 @@ This option is deprecated, use --set-key-file instead. File does not exist. - + ไม่มีแฟ้ม Cannot open file: %1 - + เปิดแฟ้มไม่ได้: %1 Cannot parse file: %1 at position %2 @@ -8615,7 +9075,7 @@ This option is deprecated, use --set-key-file instead. Wrong password - + รหัสผ่านผิด Invalid encrypted data field @@ -8667,13 +9127,89 @@ This option is deprecated, use --set-key-file instead. - Unsupported KDF type, cannot decrypt json file + Unknown passkeys error - Unknown passkeys error + Invalid KDF iterations, cannot decrypt json file + + Unsupported format, ensure your Bitwarden export is password-protected + + + + Only PBKDF and Argon2 are supported, cannot decrypt json file + + + + Reset Shortcuts + + + + Double click an action to change its shortcut + + + + Filter... + + + + Shortcut Conflict + + + + Shortcut %1 conflicts with '%2'. Overwrite shortcut? + + + + Cannot generate valid passphrases because the wordlist is too short + + + + Encrypted files are not supported. + + + + Proton Pass Import + + + + Delete plugin data? + ลบข้อมูลโปรแกรมเสริมหรือไม่ + + + Delete plugin data from Entry(s)? + + + + Passkey + + + + Format to use when exporting. Available choices are 'xml', 'csv' or 'html'. Defaults to 'xml'. + + + + start minimized to the system tray + + + + malformed string, possible unescaped delimiter + + + + missing closing delimiter + + + + %1, row: %2, column: %3 + + + + Tags + แท็ก + QtIOCompressor @@ -8709,6 +9245,37 @@ This option is deprecated, use --set-key-file instead. ความผิดพลาดภายในของ zlib + + RemoteHandler + + Command `%1` did not finish in time. Process was killed. + + + + Failed to upload merged database. Command `%1` did not finish in time. Process was killed. + + + + Invalid download parameters provided. + + + + Command `%1` failed to download database. + + + + Invalid database pointer or upload parameters provided. + + + + Command `%1` exited with status code: %2 + + + + Failed to upload merged database. Command `%1` exited with status code: %2 + + + ReportsWidgetBrowserStatistics @@ -8775,6 +9342,10 @@ This option is deprecated, use --set-key-file instead. Exclude from reports ไม่นับรวมในรายงาน + + Expire Entry(s)… + + Only show entries that have a URL @@ -8785,42 +9356,39 @@ This option is deprecated, use --set-key-file instead. Show expired entries - + แสดงรายการที่หมดอายุ (Expired) - + (หมดอายุ) + + + Delete plugin data from Entry(s)… + ReportsWidgetHealthcheck - Hover over reason to show additional details. Double-click entries to edit. - วางเมาส์เหนือเหตุผลเพื่อแสดงรายละเอียดเพิ่มเติม ดับเบิลคลิกที่รายการเพื่อแก้ไข + Show expired entries + แสดงรายการที่หมดอายุ - Bad - Password quality - เลวร้าย + (Expired) + (หมดอายุ) + + + Hover over reason to show additional details. Double-click entries to edit. + วางเมาส์เหนือเหตุผลเพื่อแสดงรายละเอียดเพิ่มเติม ดับเบิลคลิกที่รายการเพื่อแก้ไข Bad — password must be changed เลวร้าย — ต้องเปลี่ยนรหัสผ่าน - - Poor - Password quality - แย่ - Poor — password should be changed แย่ — ควรเปลี่ยนรหัสผ่าน - - Weak - Password quality - อ่อนแอ - Weak — consider changing the password อ่อนแอ — ควรพิจารณารหัสผ่านใหม่ @@ -8869,18 +9437,14 @@ This option is deprecated, use --set-key-file instead. Exclude from reports ไม่นับรวมในรายงาน - - Show expired entries - + + Expire Entry(s)… + Show entries that have been excluded from reports - - (Expired) - - ReportsWidgetHibp @@ -8976,6 +9540,10 @@ This option is deprecated, use --set-key-file instead. Exclude from reports ไม่นับรวมในรายงาน + + Expire Entry(s)… + + ReportsWidgetPasskeys @@ -9021,11 +9589,11 @@ This option is deprecated, use --set-key-file instead. Show expired entries - + แสดงรายการที่หมดอายุ (Expired) - + (หมดอายุ) Export Confirmation @@ -9217,6 +9785,14 @@ This option is deprecated, use --set-key-file instead. No agent running, cannot list identities. ไม่มีตัวแทนทำงาน ไม่สามารถระบุตัวตนได้ + + Failed to remove all SSH identities from agent. + + + + All SSH identities removed from agent. + + SearchHelpWidget @@ -9502,29 +10078,6 @@ This option is deprecated, use --set-key-file instead. ส่งออกไป %1 - - ShortcutSettingsWidget - - Double click an action to change its shortcut - - - - Shortcut Conflict - - - - Filter... - - - - Shortcut %1 conflicts with '%2'. Overwrite shortcut? - - - - Reset Shortcuts - - - TagModel @@ -9734,15 +10287,15 @@ Example: JBSWY3DPEHPK3PXP Create Database - + สร้างฐานข้อมูล Open Database - + เปิดฐานข้อมูล Import File - + นำเข้าแฟ้ม @@ -9814,11 +10367,15 @@ Example: JBSWY3DPEHPK3PXP ตรวจไม่พบกุญแจฮาร์ดแวร์ - <p>If you own a <a href="https://www.yubico.com/">YubiKey</a> or <a href="https://onlykey.io">OnlyKey</a>, you can use it for additional security.</p><p>The key requires one of its slots to be programmed as <a href="https://docs.yubico.com/yesdk/users-manual/application-otp/challenge-response.html">HMAC-SHA1 Challenge-Response</a>.</p> + Refresh hardware keys - Refresh hardware keys + <p>If you own a <a href="https://www.yubico.com/">YubiKey</a> or <a href="https://onlykey.io">OnlyKey</a>, you can use it for additional security.</p><p>The key requires one of its slots to be programmed with <a href="https://keepassxc.org/docs/#faq-yubikey-howto">Challenge-Response</a>.</p> + + + + Hardware keys found, but no slots are configured diff --git a/share/translations/keepassxc_tr.ts b/share/translations/keepassxc_tr.ts index 395ce30a1..f4c254f0a 100644 --- a/share/translations/keepassxc_tr.ts +++ b/share/translations/keepassxc_tr.ts @@ -217,18 +217,50 @@ You must restart the application to set the new language. Would you like to restart now? Yeni dilin kullanıma alınması için uygulamayı yeniden başlatmalısınız. Şimdi yeniden başlatılsın mı? - - Reset Settings? - Ayarlar sıfırlansın mı? - - - Are you sure you want to reset all general and security settings to default? - Tüm genel ve güvenlik ayarlarını varsayılan değerlerine döndürmek istediğinize emin misiniz? - Select backup storage directory Yedek kayıt klasörünü seçin + + Confirm Reset + Sıfırlamayı onayla + + + Are you sure you want to reset all settings to default? + Tüm ayarları varsayılan değerlerine döndürmek istediğinize emin misiniz? + + + Import KeePassXC Settings + KeePassXC ayarlarını içe aktar + + + Failed to import settings from %1, not a valid settings file. + Ayarlar %1 üzerinden içe aktarılamadı. Dosya geçerli bir ayar dosyası değil. + + + Export KeePassXC Settings + KeePassXC ayarlarını dışa aktar + + + Small + Küçük + + + Normal + Normal + + + Medium + Orta + + + Large + Büyük + + + Custom + Özel + ApplicationSettingsWidgetGeneral @@ -280,25 +312,6 @@ Include beta releases when checking for updates Güncelleme denetimine beta sürümleri de katılsın - - On database unlock, show entries that - Veri tabanının kilidi açıldığında, şu kayıtlar görüntülensin - - - have expired - On database unlock, show entries that... - süresi geçmiş - - - days - On database unlock, show entries that will expire within %1 days - gün - - - will expire within - On database unlock, show entries that... - Süresinin geçmesine - File Management Dosya yönetimi @@ -323,22 +336,10 @@ Backup database file before saving Kaydetmeden önce veri tabanı dosyası yedeklensin - - Backup destination - Yedek hedefi - - - Specifies the database backup file location. Occurrences of "{DB_FILENAME}" are replaced with the filename of the saved database without extension. {TIME:<format>} is replaced with the backup time, see https://doc.qt.io/qt-5/qdatetime.html#toString. <format> defaults to format string "dd_MM_yyyy_hh-mm-ss". - Veri tabanı yedek dosyasının konumunu belirtir. "{DB_FILENAME}" kodu, kayıtlı veri tabanının uzantısı olmayan dosya adı, {TIME:<format>} kodu, yedekleme zamanı ile değiştirilir. https://doc.qt.io/qt-5/qdatetime.html#toString adresine bakabilirsiniz.<format> Varsayılan biçem dizgesi "dd_MM_yyyy_hh-mm-ss". - {DB_FILENAME}.old.kdbx {DB_FILENAME}.old.kdbx - - Choose... - Seçin… - Use alternative saving method (may solve problems with Dropbox, Google Drive, GVFS, etc.) Alternatif kayıt yöntemi kullanılsın (Dropbox, Google Drive, GVFS, vb ile yaşanan sorunları çözebilir) @@ -505,6 +506,71 @@ Remember last typed entry for: Son yazılmış kaydın hatırlanma süresi: + + On database unlock, show entries that will expire within + Veri tabanının kilidi açıldığında, şu zaman içinde süresi dolacak kayıtlar görüntülensin + + + On database unlock, show entries that will expire within + Veri tabanının kilidi açıldığında, şu zaman içinde süresi dolacak kayıtlar görüntülensin + + + days + number of days warning for password expiration + gün + + + Destination format: + Hedef biçimi: + + + <html><head/><body><p><span style=" font-weight:600;">{DB_FILENAME}</span> is replaced with the filename of the saved database without extension</p><p><span style=" font-weight:600;">{TIME:&lt;format&gt;}</span> is replaced with the specified time format (default: dd_MM_yyyy_hh-mm-ss)</p><p>See the User Guide for more details</p></body></html> + <html><head/><body><p><span style=" font-weight:600;">{DB_FILENAME}</span> yerinde uzantısı olmadan kaydedilmiş veri tabanının dosya adı görüntülenir </p><p><span style=" font-weight:600;">{TIME:&lt;format&gt;}</span> yerinde belirtilen saat biçimi görüntülenir (varsayılan değer: dd_MM_yyyy_hh-mm-ss)</p><p>Ayrıntılı bilgi almak için kullanıcı rehberine bakın</p></body></html> + + + Choose folder... + Klasör seçin... + + + Show confirmation before moving entries to recycle bin + Kayıtlar geri dönüşüm kutusuna taşınmadan önce onay istensin + + + Copy data on double clicking field in entry view + Kayıt görünümünde alana çift tıklandığında veriler kopyalansın + + + Show toolbar + Araç çubuğunu görüntüle + + + Show the menu bar by pressing the Alt key + Alt tuşuna basıldığında menü çubuğu görüntülensin + + + Show menubar + Araç çubuğu görüntülensin + + + Import settings… + Ayarları içe aktar… + + + Export settings… + Ayarları dışa aktar… + + + Open browser on double clicking URL field in entry view + Kayıt görünümünde adres alanına çift tıklandığında tarayıcı açılsın + + + Font size: + Yazı boyutu: + + + Font size selection + Yazı boyutu seçimi + ApplicationSettingsWidgetSecurity @@ -570,18 +636,6 @@ Hide passwords in the entry preview panel Kayıt ön izleme panosunda parolalar gizlensin - - Hide entry notes by default - Kayıt notları varsayılan olarak gizlensin - - - Move entries to recycle bin without confirmation - Kayıtlar çöp kutusuna atılırken onay istenmesin - - - Enable double click to copy the username/password entry columns - Kullanıcı adı/parola kaydı sütunlarını kopyalamak için çift tıklama kullanılsın - Privacy Gizlilik @@ -594,6 +648,18 @@ Hide TOTP in the entry preview panel Tek kullanımlık parola kayıt ön izleme panosunda gizlensin + + Lock databases when switching user + Kullanıcı değiştirildiğinde veri tabanları kilitlensin + + + Lock Options + Seçenekleri kilitle + + + Hide notes in the entry preview panel + Notlar kayıt ön izleme panosunda gizlensin + AutoType @@ -641,20 +707,6 @@ Entry does not have attribute for PICKCHARS: %1 Kayıtta PICKCHARS için öznitelik yok: %1 - - Invalid conversion type: %1 - Dönüşüm türü geçersiz: %1 - - - Invalid conversion syntax: %1 - Dönüşüm söz dizimi geçersiz: %1 - - - Invalid regular expression syntax %1 -%2 - Kurallı ifade sözdizimi geçersiz %1 -%2 - Invalid placeholder: %1 Yer belirteci geçersiz: %1 @@ -886,24 +938,25 @@ Lütfen kimlik bilgilerinin kaydedileceği doğru veri tabanını seçin. Add to existing entry - + Var olan kayda ekle Existing passkey found. Do you want to register a new passkey for: - + Var olan bir geçiş anahtarı bulundu. +Şunun için yeni bir geçiş anahtarı kaydetmek ister misiniz: Select the existing passkey and press Update to replace it. - + Var olan geçiş anahtarını seçin ve değiştirmek için Güncelle üzerine basın. Authenticate passkey credentials for: - + Şunun için geçiş anahtarı kimlik doğrulama bilgilerine izin verilsin: Do you want to register a passkey for: - + Şunun için geçiş anahtarı kaydetmek ister misiniz: @@ -988,16 +1041,17 @@ Bu kaydın silinmesini ister misiniz? Register a new passkey to this entry: - + Şu kayıt için yeni bir geçiş anahtarı kaydet: KeePassXC - Update passkey - + KeePassXC - Geçiş anahtarı kaydını güncelle Entry already has a passkey. Do you want to overwrite the passkey in %1 - %2? - + Kaydın zaten bir geçiş anahtarı kaydı var. +%1 - %2 geçiş anahtarı kaydını değiştirmek istiyor musunuz? Register @@ -1022,10 +1076,6 @@ Do you want to overwrite the passkey in %1 - %2? General Genel - - Browsers installed as snaps are currently not supported. - Anlık olarak kurulan tarayıcılar henüz desteklenmiyor. - Enable integration for these browsers: Şu tarayıcılar için bütünleşme kullanılsın: @@ -1197,18 +1247,6 @@ Do you want to overwrite the passkey in %1 - %2? Custom extension ID Özel eklenti kimliği - - Due to Snap sandboxing, you must run a script to enable browser integration.<br />You can obtain this script from %1 - Geçici kum havuzu kullanılması nedeniyle, tarayıcı bütünleşmesini kullanmak için bir betik çalıştırmalısınız.<br />Bu betiği %1 adresinden alabilirsiniz. - - - KeePassXC-Browser is needed for the browser integration to work. <br />Download it for %1 and %2 and %3. %4 - Tarayıcı bütünleşmesinin çalışması için KeePassXC-Browser gereklidir. <br />%1, %2 ve %3 tarayıcıları için indirebilirsiniz. %4 - - - Please see special instructions for browser extension use below - Lütfen aşağıdan tarayıcı eklentisi kullanımı ile ilgili özel yönergelere bakın - Executable Files Çalıştırılabilir dosyalar @@ -1251,11 +1289,19 @@ Do you want to overwrite the passkey in %1 - %2? Allows using insecure http://localhost with passkeys for testing purposes. - + Deneme amacıyla geçiş anahtarları ile güvenli olmayan http://localhost kullanılabilsin. Allow using localhost with passkeys - + Geçiş anahtarları ile localhost kullanılabilsin + + + KeePassXC-Browser is needed for the browser integration to work. <br />Download it for %1 and %2 and %3. + Tarayıcı bütünleşmesinin çalışması için KeePassXC-Browser gereklidir. <br />%1, %2 ve %3 tarayıcıları için indirebilirsiniz. + + + Browsers installed using Snap or Flatpak are not supported with exception to Firefox installed using Snap. + Snap veya Flatpak ile kurulan tarayıcılar, Snap ile kurulan Firefox dışında, desteklenmiyor. @@ -1399,6 +1445,20 @@ Do you want to overwrite the passkey in %1 - %2? Imported from CSV file: %1 CSV dosyasından içe aktarıldı: %1 + + No Title Selected + Herhangi bir başlık seçilmemiş + + + No title column was selected, entries will be hard to tell apart. +Are you sure you want to import? + Herhangi bir başlık sütunu seçilmemiş. Kayıtları ayırmak zor olacak. +İçe aktarmak istediğinize emin misiniz? + + + Tags + Etiketler + CsvParserModel @@ -1462,6 +1522,14 @@ Yedek veri tabanının konumu %2 Recycle Bin Çöp kutusu + + Database file read error. + Veri tabanı dosyası okunurken sorun çıktı + + + No file path was provided. + Herhangi bir dosya yolu belirtilmemiş. + DatabaseOpenDialog @@ -1610,14 +1678,6 @@ Bu sorunu engellemek için, "Veri tabanı ayarları / Güvenlik" böl <p>In addition to a password, you can use a secret file to enhance the security of your database. This file can be generated in your database's security settings.</p><p>This is <strong>not</strong> your *.kdbx database file!</p> <p>Veri tabanınızın güvenliğini artırmak için parolaya ek olarak gizli bir dosya kullanabilirsiniz. Bu dosyayı veri tabanınızın güvenlik ayarları bölümünden oluşturabilirsiniz.</p><p>Bu dosya, *.kdbx veri tabanı dosyanız <strong>değildir</strong>. - - Click to add a key file. - Bir anahtar dosyası eklemek için tıklayın. - - - <a href="#" style="text-decoration: underline">I have a key file</a> - <a href="#" style="text-decoration: underline">Bir anahtar dosyam var</a> - Use hardware key [Serial: %1] Donanımsal anahtar kullanılsın [Seri: %1] @@ -1654,6 +1714,18 @@ Bu dosya ile ilerlemek istediğinize emin misiniz? Refresh Hardware Keys Donanımsal anahtarları yenile + + Click to add a key file. + Bir anahtar dosyası eklemek için tıklayın. + + + <a href="#" style="text-decoration: underline">I have a key file</a> + <a href="#" style="text-decoration: underline">Bir anahtar dosyam var</a> + + + Hardware keys found, but no slots are configured. + Donanımsal anahtar bulundu. Ancak herhangi bir yuva yapılandırılmamış. + DatabaseSettingWidgetMetaData @@ -1688,6 +1760,22 @@ Bu dosya ile ilerlemek istediğinize emin misiniz? Maintenance Bakım + + KeeShare + KeeShare + + + Secret Service Integration + Gizli hizmet bütünleşmesi + + + Remote Sync + Uzak eşitleme + + + Database Settings: %1 + Veri tabanı ayarları: %1 + DatabaseSettingsWidgetBrowser @@ -1858,14 +1946,14 @@ Bir parola ayarlamadan ilerlemek istediğinize emin misiniz? Weak password Parola kolay - - You must enter a stronger password to protect your database. - Veri tabanınızı korumak için daha zor bir parola yazmalısınız. - This is a weak password! For better protection of your secrets, you should choose a stronger password. Bu parola kolay! Bilgilerinizi daha iyi korumak için daha zor bir parola seçmelisiniz. + + The provided password does not meet the minimum quality requirement. + Belirtilen parola en düşük kalite gereksinimini karşılamıyor. + DatabaseSettingsWidgetEncryption @@ -2167,6 +2255,50 @@ veri tabanından kaldırılır. Autosave delay since last change checkbox Son değişiklikten sonraki otomatik kaydetme gecikmesi işaret kutusu + + Public Database Metadata + Herkese açık veri tabanı üst verileri + + + Warning: the following settings are not encrypted. + Uyarı: Şu ayarlar şifrelenmez. + + + Display name: + Görüntülenecek ad: + + + Publically visible display name used on the unlock dialog + Kilit açma penceresinde herkese açık olarak görüntülenen ad + + + Database public display name + Veri tabanının herkese açık görüntülenecek adı + + + Display color: + Görüntülenme rengi: + + + Publically visible color used on the unlock dialog + Kilit açma penceresinde herkese açık olarak görüntülenecek renk + + + Database public display color chooser + Veri tabanının herkese açık görüntülenecek renginin seçicisi + + + Clear + Temizle + + + Display icon: + Görüntülenecek simge: + + + Select Database Icon + Veri tabanı simgesini seçin + DatabaseSettingsWidgetKeeShare @@ -2262,6 +2394,141 @@ veri tabanından kaldırılır. Veri tabanı açıklama alanı + + DatabaseSettingsWidgetRemote + + Sync Commands + Eşitleme komutları + + + Remove + Kaldır + + + Command Settings + Komut ayarları + + + Name + Ad + + + Save + Kaydet + + + Download + İndir + + + Command: + Komut: + + + Download command field + İndirme komutu alanı + + + e.g.: "sftp user@hostname" or "scp user@hostname:DatabaseOnRemote.kdbx {TEMP_DATABASE}" + Örnek: "sftp kullaniciadi@sunucu" ya da "scp kullaniciadi@sunucu:UzakVeriTabanı.kdbx {TEMP_DATABASE}" + + + Input: + Giriş: + + + Download input field + İndirme giriş alanı + + + Upload + Yükle + + + Upload command field + Yükleme komutu alanı + + + e.g.: "sftp user@hostname" or "scp {TEMP_DATABASE} user@hostname:DatabaseOnRemote.kdbx" + Örnek: "sftp kullaniciadi@sunucu" ya da "scp {TEMP_DATABASE} kullaniciadi@sunucu:UzakVeriTabanı.kdbx" + + + Upload input field + Yükleme giriş alanı + + + Name cannot be empty. + Ad boş olamaz. + + + Test + Sına + + + Download command cannot be empty. + İndirme komutu boş olamaz. + + + Download failed with error: %1 + İndirme sırasında sorun çıktı: %1 + + + Download finished, but file %1 could not be found. + İndirme tamamlandı ancak %1 dosyası bulunamadı. + + + Download successful. + İndirme tamamlandı. + + + Save Remote Settings + Uzak ayarları kaydet + + + You have unsaved changes. Do you want to save them? + Kaydedilmemiş değişiklikler var. Kaydetmek ister misiniz? + + + e.g.: +get DatabaseOnRemote.kdbx {TEMP_DATABASE} +exit +--- +{TEMP_DATABASE} is used as placeholder to store the database in a temporary location +The command has to exit. In case of `sftp` as last command `exit` has to be sent + + Örnek: +get UzakVeriTabani.kdbx {TEMP_DATABASE} +exit +--- +{TEMP_DATABASE} veri tabanını geçici bir konuma kaydetmek için yer belirtci olarak kullanılır +`sftp` kullanıldığında son komutun `exit` olması gerektiğinden, komutta exit bulunmalıdır. + + + + e.g.: +put {TEMP_DATABASE} DatabaseOnRemote.kdbx +exit +--- +{TEMP_DATABASE} is used as placeholder to store the database in a temporary location +The command has to exit. In case of `sftp` as last command `exit` has to be sent + + Örnek: +put {TEMP_DATABASE} UzakVeriTabani.kdbx +exit +--- +{TEMP_DATABASE} veri tabanını geçici bir konuma kaydetmek için yer belirtci olarak kullanılır +`sftp` kullanıldığında son komutun `exit` olması gerektiğinden, komutta exit bulunmalıdır. + + + + Timeout: + Zaman aşımı: + + + seconds + saniye + + DatabaseTabWidget @@ -2335,6 +2602,11 @@ Bu kesinlikle bir uygulama hatasıdır. Lütfen geliştiricilere bildirin.Database tab name modifier %1 [Kilitli] + + %1 [Temporary] + Database tab name modifier + %1 [Temporary] + DatabaseWidget @@ -2458,26 +2730,6 @@ Değişiklikler kaydedilsin mi? File has changed Dosya değişmiş - - The database file has changed. Do you want to load the changes? - Veri tabanı dosyası değiştirilmiş. Değişiklikleri yüklemek ister misiniz? - - - Merge Request - Birleştirme isteği - - - The database file has changed and you have unsaved changes. -Do you want to merge your changes? - Veri tabanı dosyası değiştirilmiş ve kaydedilmemiş değişiklikleriniz var. -Değişikliklerinizi birleştirmek ister misiniz? - - - Could not open the new database file while attempting to autoreload. -Error: %1 - Otomatik yüklenmeye çalışılırken yeni veri tabanı dosyası açılamadı. -Hata: %1 - Disable safe saves? Güvenli kaydetme kapatılsın mı? @@ -2529,6 +2781,86 @@ Güvenli kaydetme kapatılarak yeniden denensin mi? Database tab name modifier %1 [Yeni veri tabanı] + + Remote Sync did not contain any download or upload commands. + Uzak eşitlemede herhangi bir indirme ya da yükleme komutu bulunmuyor. + + + Remote sync '%1' completed successfully! + '%1' uzak eşitlemesi tamamlandı! + + + Remote sync '%1' failed: %2 + '%1' uzak eşitlemesi tamamlanamadı: %2 + + + Error while saving database %1: %2 + %1 veri tabanı kaydedilirken sorun çıktı: %2 + + + Downloading... + İndiriliyor... + + + Uploading... + Yükleniyor... + + + Syncing... + Eşitleniyor... + + + Remove passkey from entry + Kaydın geçiş anahtarını kaldır + + + Do you want to remove the passkey from this entry? + Geçiş anahtarını bu kayıttan kaldırmak istediğinize emin misiniz? + + + The database file "%1" was modified externally + "%1" veri tabanı dosyası dışarıdan değiştirilmiş + + + Do you want to load the changes? + Değişiklikleri yüklemek ister misiniz? + + + Reload database + Veri tabanını yeniden yükle + + + Reloading database… + Veri tabanı yeniden yükleniyor… + + + Reload canceled + Yeniden yükleme iptal edildi + + + Reload successful + Yeniden yüklendi + + + Reload pending user action… + Yeniden yükleme için kullanıcı işlemi bekleniyor… + + + The database file "%1" was modified externally.<br>How would you like to proceed?<br><br>Merge all changes<br>Ignore the changes on disk until save<br>Discard unsaved changes + "%1" veri tabanı dosyası dışarıdan değiştirilmiş.<br>Nasıl ilerlemek istersiniz?<br><br>Tüm değişiklikler birleştirilsin<br>Kaydedilinceye kadar diskteki değişiklikler yok sayılsın<br>Kaydedilmemiş değişiklikler silinsin + + + The database file "%1" was modified externally.<br>How would you like to proceed?<br><br>Merge all changes then save<br>Overwrite the changes on disk<br>Discard unsaved changes + "%1" veri tabanı dosyası dışarıdan değiştirilmiş.<br>Nasıl ilerlemek istersiniz?<br><br>Tüm değişiklikler birleştirilsin ve kaydedilsin<br>Diskteki değişikliklerin üzerine yazılsın<br>Kaydedilmemiş değişiklikler silinsin + + + Database file overwritten. + Veri tabanı dosyasının üzerine yazıldı. + + + Database file on disk cannot be unlocked with current credentials.<br>Enter new credentials and/or present hardware key to continue. + Diskteki veri tabanı dosyası geçerli kimlik doğrulama bilgileriyle açılamadı.<br>İlerlemek için yeni kimlik doğrulama bilgilerini yazın ve/veya geçerli donanım anahtarını kullanın. + EditEntryWidget @@ -2580,10 +2912,6 @@ Güvenli kaydetme kapatılarak yeniden denensin mi? n/a yok - - (encrypted) - (şifrelenmiş) - Select private key Kişisel anahtarı seçin @@ -2686,6 +3014,10 @@ Düzeltmek ister misiniz? %n year(s) %n yıl%n yıl + + Failed to decrypt SSH key, ensure password is correct. + SSH anahtarının şifresi çözülemedi. Parolanın doğru olduğundan emin olun. + EditEntryWidgetAdvanced @@ -2857,18 +3189,10 @@ Düzeltmek ister misiniz? Skip Auto-Submit for this entry Bu kayıt için otomatik gönderim yapılmasın - - Only send this setting to the browser for HTTP Auth dialogs. If enabled, normal login forms will not show this entry for selection. - Bu ayar tarayıcıya yalnızca HRRP Auth pencereleri için gönderilir. Bu seçenek açıldığında, bu kayıt normal oturum açma formlarında seçilmek üzere görüntülenmez. - Use this entry only with HTTP Basic Auth Bu kayıt yalnızca HTTP temel kimlik doğrulaması ile kullanılsın - - Do not send this setting to the browser for HTTP Auth dialogs. If enabled, HTTP Auth dialogs will not show this entry for selection. - Bu ayar tarayıcıya HTTP kimlik doğrulama pencereleri için gönderilmez. Bu seçenek açıldığında, bu kayıt HTTP kimlik doğrulama pencerelerinde seçilmek üzere görüntülenmez. - Do not use this entry with HTTP Basic Auth Bu kayıt HTTP temel kimlik doğrulaması ile kullanılmasın @@ -2893,6 +3217,14 @@ Düzeltmek ister misiniz? Additional URLs Ek adresler + + Only send this entry to the browser for HTTP Auth dialogs. If enabled, normal login forms will not show this entry for selection. + Bu kayıt tarayıcıya yalnızca HRRP Auth pencereleri için gönderilir. Bu seçenek açıldığında, bu kayıt normal oturum açma formlarında seçilmek üzere görüntülenmez. + + + Do not send this entry to the browser for HTTP Auth dialogs. If enabled, HTTP Auth dialogs will not show this entry for selection. + Bu kayıt tarayıcıya HTTP kimlik doğrulama pencereleri için gönderilmez. Bu seçenek açıldığında, bu kayıt HTTP kimlik doğrulama pencerelerinde seçilmek üzere görüntülenmez. + EditEntryWidgetHistory @@ -3115,6 +3447,10 @@ Düzeltmek ister misiniz? seconds saniye + + Clear agent + Uygulamayı temizle + EditGroupWidget @@ -3557,6 +3893,24 @@ Bu işlem etkilenecek eklentilerin bozulmasına neden olabilir. %1 - Clone Kopya - %1 + + Passkey + Geçiş anahtarı + + + Invalid conversion type: %1 + Dönüşüm türü geçersiz: %1 + + + Invalid conversion syntax: %1 + Dönüşüm söz dizimi geçersiz: %1 + + + Invalid regular expression syntax %1 +%2 + Kurallı ifade sözdizimi geçersiz %1 +%2 + EntryAttachments @@ -3565,6 +3919,21 @@ Bu işlem etkilenecek eklentilerin bozulmasına neden olabilir. "%1" dosyası açılamadı + + EntryAttachmentsDialog + + Form + Form + + + File name + Dosya adı + + + File contents... + Dosya içerikleri... + + EntryAttachmentsModel @@ -3602,14 +3971,6 @@ Bu işlem etkilenecek eklentilerin bozulmasına neden olabilir. Remove Kaldır - - Rename selected attachment - Seçilmiş ek dosyayı yeniden adlandır - - - Rename - Yeniden adlandır - Open selected attachment Seçilmiş ek dosyayı aç @@ -3725,6 +4086,18 @@ Would you like to overwrite the existing attachment? "%1" ek dosyası zaten var. Var olan ek dosyanın üzerine yazılmasını ister misiniz? + + New + Yeni + + + Preview + Ön izleme + + + Failed to preview an attachment: Attachment not found + Bir ek dosya ön izlemesi görüntülenemedi: Ek dosya bulunamadı + EntryAttributesModel @@ -3923,6 +4296,10 @@ Var olan ek dosyanın üzerine yazılmasını ister misiniz? Background Color Arka plan rengi + + Group Path + Grup yolu + EntryPreviewWidget @@ -4225,7 +4602,7 @@ Bu işlem, parolalarınızı ve önemli bilgilerinizi korumasız kılacak! HibpDownloader Online password validation failed - Parola çevrimiçi olarak onaylanamadı + Parola çevrim içi olarak onaylanamadı @@ -4318,6 +4695,14 @@ Uygulama ayarlarındaki güvenlik bölümünden DuckDuckGo site simge hizmetini Url Adres + + Could not load key file. + Anahtar dosyası yüklenemedi. + + + Could not open remote database. Password or key file may be incorrect. + Uzak veri tabanı açılamadı. Parola ya da anahtar dosyası doğru olmayabilir. + ImportWizardPageSelect @@ -4421,6 +4806,49 @@ Uygulama ayarlarındaki güvenlik bölümünden DuckDuckGo site simge hizmetini KeePass1 Database KeePass1 veri tabanı + + Proton Pass (.json) + Proton Pass (.json) + + + Proton Pass JSON Export + Proton Pass JSON dışa aktarımı + + + Temporary Database + Geçici veri tabanı + + + Command: + Komut: + + + e.g.: "sftp user@hostname" or "scp user@hostname:DatabaseOnRemote.kdbx {TEMP_DATABASE}" + Örnek: "sftp kullaniciadi@sunucu" ya da "scp kullaniciadi@sunucu:UzakVeriTabanı.kdbx {TEMP_DATABASE}" + + + Input: + Giriş: + + + e.g.: +get DatabaseOnRemote.kdbx {TEMP_DATABASE} +exit +--- +{TEMP_DATABASE} is used as placeholder to store the database in a temporary location +The command has to exit. In case of `sftp` as last commend `exit` has to be sent + + Örnek: +get UzakVeriTabanı.kdbx {TEMP_DATABASE} +exit +--- +{TEMP_DATABASE}, veri tabanını geçici bir konumda depolamak için yer belirtici olarak kullanılır +Komuttan çıkılması gerekir. `sftp` durumunda son komut olarak `exit` gönderilmelidir + + + Remote Database (.kdbx) + Uzak veri tabanı (.kdbx) + KMessageWidget @@ -5458,7 +5886,7 @@ Bu dosyayı kullanarak ilerlemek istediğinize emin misiniz? &Online Help - &Çevrimiçi yardım + &Çevrim içi yardım &User Guide @@ -5561,12 +5989,6 @@ Bu sürüm, günlük kullanım için uygun değildir. Expect some bugs and minor issues, this version is meant for testing purposes. NOT: Yayın öncesi bir KeePassXC sürümü kullanıyorsunuz! Bazı hatalar ve küçük sorunlarla karşılaşabilirsiniz. Bu sürüm deneme amacıyla yayınlanmıştır. - - - WARNING: Your Qt version may cause KeePassXC to crash with an On-Screen Keyboard. -We recommend you use the AppImage available on our downloads page. - UYARI: Kullandığınız Qt sürümü KeePassXC ekran klavyesinin çökmesine neden olabilir. -KeePassXC indirme sayfasında bulunan AppImage paketini kullanmanız önerilir. No Tags @@ -5640,6 +6062,10 @@ KeePassXC indirme sayfasında bulunan AppImage paketini kullanmanız önerilir.< Import Passkey Geçiş anahtarı içe aktar + + Remote S&ync… + &Uzak eşitleme… + Quit Application Uygulamadan çık @@ -5744,6 +6170,10 @@ KeePassXC indirme sayfasında bulunan AppImage paketini kullanmanız önerilir.< Show Password Generator Parola oluşturucuyu görüntüle + + Remove Passkey From Entry + Kaydın geçiş anahtarını kaldır + Perform Auto-Type: {USERNAME} Otomatik yaz: {USERNAME} @@ -5888,6 +6318,34 @@ KeePassXC indirme sayfasında bulunan AppImage paketini kullanmanız önerilir.< Toggle Allow Screen Capture Ekran görüntüsü almayı aç/kapat + + Show Group Panel + Grup panosu görüntülensin + + + Toggle Show Group Panel + Grup panosunu görüntüle/gizle + + + Setup Remote Sync… + Uzak eşitlemeyi kur... + + + Password Generator + Parola oluşturucu + + + E&xpire Entry… + Kayıt &geçerlilik süresi… + + + Clear SSH Agent + SSH uygulamasını temizle + + + Clear all identities in ssh-agent + SSH uygulamasındaki tüm kimlikleri temizle + ManageDatabase @@ -6038,6 +6496,25 @@ KeePassXC indirme sayfasında bulunan AppImage paketini kullanmanız önerilir.< Lütfen yeni veri tabanı için görüntülenecek bir ad ve isteğe bağlı bir açıklama yazın: + + NewEntryAttachmentsDialog + + Attachment name cannot be empty + Ek dosya adı boş olamaz + + + Attachment with the same name already exists + Aynı adlı bir ek dosya zaten var + + + Save attachment + Ek dosyayı kaydet + + + New entry attachment + Yeni kayıt ek dosyası + + NixUtils @@ -6225,6 +6702,10 @@ KeePassXC indirme sayfasında bulunan AppImage paketini kullanmanız önerilir.< Unexpected EOF when writing private key Kişisel anahtar yazılırken dosya beklenmedik şekilde sonlandı + + (encrypted) + (şifrelenmiş) + OpenSSHKeyGenDialog @@ -6273,7 +6754,7 @@ KeePassXC indirme sayfasında bulunan AppImage paketini kullanmanız önerilir.< Export the following passkey entries. - + Şu geçiş anahtarı kayıtlarını dışa aktar. @@ -6347,15 +6828,15 @@ Do you want to overwrite it? Import the following passkey: - + Şu geçiş anahtarı kaydını içe aktar: Import the following passkey to this entry: - + Bu kayıt için şu geçiş anahtarı kaydını içe aktar: Default passkeys group (Imported Passkeys) - + Varsayılan geçiş anahtarı grubu (içe aktarılmış geçiş anahtarları) @@ -6378,25 +6859,27 @@ Do you want to overwrite it? Open passkey file - + Geçiş anahtarı dosyasını aç Cannot import passkey - + Geçiş anahtarı içe aktarılamadı Cannot import passkey file "%1". Data is missing. - + "%1" geçiş anahtarı dosyası içe aktarılamadı. Veriler eksik. Cannot import passkey file "%1". The following data is missing: %2 - + "%1" geçiş anahtarı dosyası içe aktarılamadı. +Şu veriler eksik: +%2 Cannot import passkey file "%1". Private key is missing or malformed. - + "%1" geçiş anahtarı dosyası içe aktarılamadı. Kişisel anahtar eksik ya da bozuk. @@ -6577,10 +7060,6 @@ The following data is missing: Also choose from: Aynı şuradan seçilsin: - - Excluded characters: "0", "1", "l", "I", "O", "|", "﹒" - Katılmayacak karakterler: "0", "1", "l", "I", "O", "|", "﹒" - Exclude look-alike characters Benzer görünen karakterler katılmasın @@ -6605,10 +7084,6 @@ The following data is missing: Word Count: Sözcük sayısı: - - Character Count: - Karakter sayısı: - Word Case: Sözcük biçimi: @@ -6621,10 +7096,6 @@ The following data is missing: Add custom wordlist Özel sözcük listesi ekle - - character - karakter - Close Kapat @@ -6731,6 +7202,22 @@ Do you want to overwrite it? Special Characters Özel karakterler + + passwordLength + parolaUzunluğu + + + Characters: %1 + Karakter sayısı: %1 + + + MIXED case + Büyük/küçük karışık + + + Excluded characters: "0", "1", "l", "I", "O", "|", "﹒", "B", "8", "G", "6" + Katılmayacak karakterler: "0", "1", "l", "I", "O", "|", "﹒", "B", "8", "G", "6" + PasswordWidget @@ -6798,6 +7285,21 @@ Do you want to overwrite it? Karakterler arasında &Sekme gönderilsin + + PreviewEntryAttachmentsDialog + + Preview entry attachment + Kayıt ek dosyaları ön izlemesi + + + No preview available + Ön izleme yok + + + Image format not supported + Görsel biçimi desteklenmiyor + + QMessageBox @@ -7476,10 +7978,6 @@ Do you want to overwrite it? Invalid word count %1 Geçersiz sözcük sayısı %1 - - The word list is too small (< 1000 items) - Sözcük listesi çok küçük (< 1000 öge) - Title for the entry. Kaydın başlığı. @@ -7624,10 +8122,6 @@ Do you want to overwrite it? Exit interactive mode. Etkileşimli kipten çık. - - Format to use when exporting. Available choices are 'xml' or 'csv'. Defaults to 'xml'. - Dışa aktarmada kullanılacak biçim. Kullanılabilecek seçenekler 'xml' ya da 'csv'. Varsayılan biçim: 'xml'. - Exports the content of a database to standard output in the specified format. Bir veri tabanının içeriğini belirtilen biçimde standart çıkışa aktarır. @@ -8216,18 +8710,6 @@ Kernel: %3 %4 file empty dosya boş - - malformed string - dizge bozuk - - - missing closing quote - tırnak kapatma eksik - - - %1: (row, col) %2,%3 - %1: (satır, sütun) %2,%3 - AES 256-bit AES 256-bit @@ -8673,12 +9155,88 @@ Bu seçenekler kullanımdan kaldırıldı. yerine --set-key-file kullanın.Kısayollar - Unsupported KDF type, cannot decrypt json file - KDF türü desteklenmiyor. JSON dosyasının şifresi çözülemedi + Unknown passkeys error + Bilinmeyen geçiş anahtarları sorunu - Unknown passkeys error - + Invalid KDF iterations, cannot decrypt json file + Anahtar türetme işlevi döngüleri geçersiz. JSON dosyasının şifresi çözülemedi + + + Unsupported format, ensure your Bitwarden export is password-protected + Biçim desteklenmiyor. Bitwarden dışa aktarımınızın parola ile korunduğundan emin olun + + + Only PBKDF and Argon2 are supported, cannot decrypt json file + Yalnızca PBKDF ve Argon2 desteklenir. JSON dosyasının şifresi çözülemedi + + + Reset Shortcuts + Kısayolları sıfırla + + + Double click an action to change its shortcut + Kısayolunu değiştirmek istediğiniz işleme çift tıklayın + + + Filter... + Süz... + + + Shortcut Conflict + Kısayol çakışması + + + Shortcut %1 conflicts with '%2'. Overwrite shortcut? + %1 kısayolu '%2' ile çakışıyor. Kısayol değiştirilsin mi? + + + Cannot generate valid passphrases because the wordlist is too short + Sözcük listesi çok kısa olduğundan geçerli parola ifadeleri oluşturulamıyor + + + Encrypted files are not supported. + Şifrelenmiş dosyalar desteklenmez. + + + Proton Pass Import + Proton Pass içe aktarma + + + Delete plugin data? + Eklenti verileri silinsin mi? + + + Delete plugin data from Entry(s)? + Kayıtlardan eklenti verileri silinsin mi?Kayıtlardan eklenti verileri silinsin mi? + + + Passkey + Geçiş anahtarı + + + Format to use when exporting. Available choices are 'xml', 'csv' or 'html'. Defaults to 'xml'. + Dışa aktarmada kullanılacak biçim. Kullanılabilecek seçenekler 'xml', 'csv' ya da 'html'. Varsayılan biçim: 'xml'. + + + start minimized to the system tray + sistem tepsisine küçültülmüş olarak başlatılsın + + + malformed string, possible unescaped delimiter + dizge bozuk, büyük olasılıkla kaçış karakteri olmayan tırnak var + + + missing closing delimiter + kapanış tırnağı eksik + + + %1, row: %2, column: %3 + %1, %2. satır, %3. sütun + + + Tags + Etiketler @@ -8715,6 +9273,37 @@ Bu seçenekler kullanımdan kaldırıldı. yerine --set-key-file kullanın.İç zlib sorunu çıktı: + + RemoteHandler + + Command `%1` did not finish in time. Process was killed. + `%1` komutu zamanında tamamlanamadı. İşlem sonlandırıldı. + + + Failed to upload merged database. Command `%1` did not finish in time. Process was killed. + Birleştirilen veri tabanı yüklenemedi. `%1` komutu zamanında tamamlanamadı. İşlem sonlandırıldı. + + + Invalid download parameters provided. + Belirtilen indirme parametreleri geçersiz. + + + Command `%1` failed to download database. + `%1` komutu veri tabanını indiremedi. + + + Invalid database pointer or upload parameters provided. + Veri tabanı göstergesi ya da belirtilen yükleme parametreleri geçersiz. + + + Command `%1` exited with status code: %2 + `%1` komutundan şu durum kodu ile çıkıldı: %2 + + + Failed to upload merged database. Command `%1` exited with status code: %2 + Birleştirilen veri tabanı yüklenemedi. `%1` komutundan şu durum kodu ile çıkıldı: %2 + + ReportsWidgetBrowserStatistics @@ -8781,6 +9370,10 @@ Bu seçenekler kullanımdan kaldırıldı. yerine --set-key-file kullanın.Exclude from reports Raporlara katılmasın + + Expire Entry(s)… + Kayıt geçerlilik süresi…Kayıtların geçerlilik süresi… + Only show entries that have a URL Yalnızca adresi olan kayıtlar görüntülensin @@ -8797,36 +9390,33 @@ Bu seçenekler kullanımdan kaldırıldı. yerine --set-key-file kullanın. (Expired) (Süresi geçmiş) + + Delete plugin data from Entry(s)… + Kayıtlardan eklenti verileri silinsin…Kayıtlardan eklenti verileri silinsin… + ReportsWidgetHealthcheck - Hover over reason to show additional details. Double-click entries to edit. - Ayrıntıları görüntülemek için fareyi neden üzerinde gezdirin. Kaydı düzenlemek için çift tıklayın. + Show expired entries + Süresi geçmiş kayıtlar görüntülensin - Bad - Password quality - Kötü + (Expired) + (Süresi geçmiş) + + + Hover over reason to show additional details. Double-click entries to edit. + Ayrıntıları görüntülemek için fareyi neden üzerinde gezdirin. Kaydı düzenlemek için çift tıklayın. Bad — password must be changed Kötü — Parola mutlaka değiştirilmeli - - Poor - Password quality - Çok kolay - Poor — password should be changed Çok kolay — Parola değiştirilmeli - - Weak - Password quality - Kolay - Weak — consider changing the password Kolay — Parolayı değiştirmeyi değerlendirin @@ -8875,28 +9465,24 @@ Bu seçenekler kullanımdan kaldırıldı. yerine --set-key-file kullanın.Exclude from reports Raporlara katılmasın - - Show expired entries - Süresi geçmiş kayıtlar görüntülensin + + Expire Entry(s)… + Kayıt geçerlilik süresi…Kayıtların geçerlilik süresi… Show entries that have been excluded from reports Raporlara katılmayan kayıtlar görüntülensin - - (Expired) - (Süresi geçmiş) - ReportsWidgetHibp CAUTION: This report requires sending information to the Have I Been Pwned online service (https://haveibeenpwned.com). If you proceed, your database passwords will be cryptographically hashed and the first five characters of those hashes will be sent securely to this service. Your database remains secure and cannot be reconstituted from this information. However, the number of passwords you send and your IP address will be exposed to this service. - UYARI: Bu rapor için "Have I Been Pwned" çevrimiçi hizmetine (https://haveibeenpwned.com) bilgi gönderilmesi gerekir. İlerlediğinizde, veri tabanı parolalarınız şifreli olarak karıştırılır ve bu karmanın ilk beş karakteri güvenli olarak bu hizmete gönderilir. Veri tabanınız güvende kalır ve gönderilen bilgiler ile yeniden oluşturulamaz. Yalnızca, gönderdiğiniz parolaların sayısı ve IP adresiniz bu hizmete bildirilir. + UYARI: Bu rapor için "Have I Been Pwned" çevrim içi hizmetine (https://haveibeenpwned.com) bilgi gönderilmesi gerekir. İlerlediğinizde, veri tabanı parolalarınız şifreli olarak karıştırılır ve bu karmanın ilk beş karakteri güvenli olarak bu hizmete gönderilir. Veri tabanınız güvende kalır ve gönderilen bilgiler ile yeniden oluşturulamaz. Yalnızca, gönderdiğiniz parolaların sayısı ve IP adresiniz bu hizmete bildirilir. Perform Online Analysis - Çevrimiçi incelemeden geçirin + Çevrim içi incelemeden geçirin Also show entries that have been excluded from reports @@ -8982,6 +9568,10 @@ Bu seçenekler kullanımdan kaldırıldı. yerine --set-key-file kullanın.Exclude from reports Raporlara katılmasın + + Expire Entry(s)… + Kayıt geçerlilik süresi…Kayıtların geçerlilik süresi… + ReportsWidgetPasskeys @@ -9043,11 +9633,11 @@ Bu seçenekler kullanımdan kaldırıldı. yerine --set-key-file kullanın. Please wait, list of entries with passkeys is being updated… - + Lütfen geçiş anahtarı bulunan kayıtların listesi güncellenirken bekleyin... No entries with passkeys. - + Geçiş anahtarı bulunan bir kayıt yok. @@ -9223,6 +9813,14 @@ Bu seçenekler kullanımdan kaldırıldı. yerine --set-key-file kullanın.No agent running, cannot list identities. Çalışan bir uygulama yok. Kimlikler listelenemedi. + + Failed to remove all SSH identities from agent. + Uygulamadaki tüm SSH kimlikleri silinemedi. + + + All SSH identities removed from agent. + Uygulamadaki tüm SSH kimlikleri silindi. + SearchHelpWidget @@ -9508,29 +10106,6 @@ Bu seçenekler kullanımdan kaldırıldı. yerine --set-key-file kullanın.%1 üzerine dışa aktar - - ShortcutSettingsWidget - - Double click an action to change its shortcut - Kısayolunu değiştirmek istediğiniz işleme çift tıklayın - - - Shortcut Conflict - Kısayol çakışması - - - Filter... - Süz... - - - Shortcut %1 conflicts with '%2'. Overwrite shortcut? - %1 kısayolu '%2' ile çakışıyor. Kısayol değiştirilsin mi? - - - Reset Shortcuts - Kısayolları sıfırla - - TagModel @@ -9819,14 +10394,18 @@ Example: JBSWY3DPEHPK3PXP No hardware keys detected Herhangi bir donanımsal anahtar algılanamadı - - <p>If you own a <a href="https://www.yubico.com/">YubiKey</a> or <a href="https://onlykey.io">OnlyKey</a>, you can use it for additional security.</p><p>The key requires one of its slots to be programmed as <a href="https://docs.yubico.com/yesdk/users-manual/application-otp/challenge-response.html">HMAC-SHA1 Challenge-Response</a>.</p> - <p>Bir <a href="https://www.yubico.com/">YubiKey</a> ya da <a href="https://onlykey.io">OnlyKey</a> aygıtınız varsa, ek güvenlik sağlamak için kullanabilirsiniz.</p><p>Anahtar yuvalarından birinin <a href="https://docs.yubico.com/yesdk/users-manual/application-otp/challenge-response.html">HMAC-SHA1 soru/yanıt</a> olarak programlanması gerekir.</p> - Refresh hardware keys Donanımsal anahtarları yenile + + <p>If you own a <a href="https://www.yubico.com/">YubiKey</a> or <a href="https://onlykey.io">OnlyKey</a>, you can use it for additional security.</p><p>The key requires one of its slots to be programmed with <a href="https://keepassxc.org/docs/#faq-yubikey-howto">Challenge-Response</a>.</p> + <p>Bir <a href="https://www.yubico.com/">YubiKey</a> ya da <a href="https://onlykey.io">OnlyKey</a> aygıtınız varsa, ek güvenlik sağlamak için kullanabilirsiniz.</p><p>Anahtar yuvalarından birinin <a href="https://www.yubico.com/products/services-software/challenge-response/">soru/yanıt</a> olarak programlanması gerekir.</p> + + + Hardware keys found, but no slots are configured + Donanımsal anahtar bulundu. Ancak herhangi bir yuva yapılandırılmamış + YubiKeyInterfacePCSC diff --git a/share/translations/keepassxc_uk.ts b/share/translations/keepassxc_uk.ts index e56499f56..8c34fa432 100644 --- a/share/translations/keepassxc_uk.ts +++ b/share/translations/keepassxc_uk.ts @@ -217,18 +217,50 @@ You must restart the application to set the new language. Would you like to restart now? Для встановлення нової мови потрібно перезапустити програму. Бажаєте перезапустити зараз? - - Reset Settings? - Скинути налаштування? - - - Are you sure you want to reset all general and security settings to default? - Ви дійсно хочете відновити всі типові налаштування програми? - Select backup storage directory Виберіть каталог для резервного копіювання + + Confirm Reset + Підтвердити скидання + + + Are you sure you want to reset all settings to default? + Впевнені, що хочете відновити всі налаштування за замовчуванням? + + + Import KeePassXC Settings + Імпортувати налаштування KeePassXC + + + Failed to import settings from %1, not a valid settings file. + Не вдалося імпортувати налаштування з %1, неправильний файл налаштувань. + + + Export KeePassXC Settings + Експортувати налаштування KeePassXC + + + Small + + + + Normal + + + + Medium + + + + Large + + + + Custom + + ApplicationSettingsWidgetGeneral @@ -280,25 +312,6 @@ Include beta releases when checking for updates Пропонувати бета-версії для оновлення - - On database unlock, show entries that - При розблокуванні бази даних показати записи, які - - - have expired - On database unlock, show entries that... - протерміновані - - - days - On database unlock, show entries that will expire within %1 days - дні - - - will expire within - On database unlock, show entries that... - термін дії завершиться через - File Management Керування файлами @@ -323,22 +336,10 @@ Backup database file before saving Створювати резервну копію бази даних перед збереженням - - Backup destination - Шлях резервного копіювання - - - Specifies the database backup file location. Occurrences of "{DB_FILENAME}" are replaced with the filename of the saved database without extension. {TIME:<format>} is replaced with the backup time, see https://doc.qt.io/qt-5/qdatetime.html#toString. <format> defaults to format string "dd_MM_yyyy_hh-mm-ss". - Вказує розташування файлу резервної копії бази даних. Входження "{DB_FILENAME}" замінюються назвою файлу збереженої бази даних без розширення файлу. {TIME:<format>} замінюється часом резервної копії. Перегляньте https://doc.qt.io/qt-5/qdatetime.html#toString. <format> типові значення рядка формату "dd_MM_yyyy_hh-mm-ss". - {DB_FILENAME}.old.kdbx {DB_FILENAME}.old.kdbx - - Choose... - Обрати... - Use alternative saving method (may solve problems with Dropbox, Google Drive, GVFS, etc.) Використовувати альтернативний спосіб збереження (може розв'язати проблеми з Dropbox, Google Диском, GVFS та ін.) @@ -505,6 +506,71 @@ Remember last typed entry for: Пам'ятати останній введений запис для: + + On database unlock, show entries that will expire within + При розблокуванні бази даних показувати записи, термін дії яких закінчується протягом + + + On database unlock, show entries that will expire within + При розблокуванні бази даних показувати записи, термін дії яких закінчується протягом + + + days + number of days warning for password expiration + дні + + + Destination format: + Формат призначення: + + + <html><head/><body><p><span style=" font-weight:600;">{DB_FILENAME}</span> is replaced with the filename of the saved database without extension</p><p><span style=" font-weight:600;">{TIME:&lt;format&gt;}</span> is replaced with the specified time format (default: dd_MM_yyyy_hh-mm-ss)</p><p>See the User Guide for more details</p></body></html> + <html><head/><body><p><span style=" font-weight:600;">{DB_FILENAME}</span> замінюється на ім'я файла збереженої бази даних без розширення</p><p><span style=" font-weight:600;">{TIME:&lt;format&gt;}</span> замінюється на вказаний формат часу (за замовчуванням: дд_ММ_рррр_чч-хх-сс)</p><p>Дивіться Посібник користувача для більш детальної інформації</p></body></html> + + + Choose folder... + Вибрати папку... + + + Show confirmation before moving entries to recycle bin + Показувати підтвердження перед переміщенням записів до кошика + + + Copy data on double clicking field in entry view + Копіювати дані подвійним кліком по полю перегляду записів + + + Show toolbar + Показати панель инструментів + + + Show the menu bar by pressing the Alt key + Показати рядок меню при натисканні клавіші Alt + + + Show menubar + Показати меню + + + Import settings… + Імпорт налаштувань... + + + Export settings… + Експорт налаштувань... + + + Open browser on double clicking URL field in entry view + Відкрити Браузер подвійним кліком на полі URL-адреси при перегляді записів + + + Font size: + + + + Font size selection + + ApplicationSettingsWidgetSecurity @@ -570,18 +636,6 @@ Hide passwords in the entry preview panel Приховувати паролі на панелі перегляду запису - - Hide entry notes by default - Типово приховувати нотатки запису - - - Move entries to recycle bin without confirmation - Переміщувати записи до смітника без підтвердження - - - Enable double click to copy the username/password entry columns - Увімкнути подвійний клік, щоб скопіювати імʼя користувача/пароль - Privacy Приватність @@ -594,6 +648,18 @@ Hide TOTP in the entry preview panel Приховувати TOTP на панелі перегляду запису + + Lock databases when switching user + Блокування баз даних при зміні користувача + + + Lock Options + Параметри блокування + + + Hide notes in the entry preview panel + Приховати нотатки на панелі попереднього перегляду + AutoType @@ -641,20 +707,6 @@ Entry does not have attribute for PICKCHARS: %1 Запис не має атрибуту для PICKCHARS: %1 - - Invalid conversion type: %1 - Неприпустимий тип перетворення: %1 - - - Invalid conversion syntax: %1 - Неприпустимий синтаксис перетворення: %1 - - - Invalid regular expression syntax %1 -%2 - Неприпустимий синтаксис регулярного виразу %1 -%2 - Invalid placeholder: %1 Неприпустимий заповнювач: %1 @@ -714,7 +766,7 @@ Trying to send invalid keyboard symbol. - + Спроба надіслати недійсний символ клавіатури. @@ -886,24 +938,25 @@ Please select the correct database for saving credentials. Add to existing entry - + Додати до існуючого запису Existing passkey found. Do you want to register a new passkey for: - + Знайдено існуючий пароль. +Ви хочете зареєструвати новий пароль для: Select the existing passkey and press Update to replace it. - + Виберіть існуючий пароль і натисніть "Оновити", щоб замінити його. Authenticate passkey credentials for: - + Аутентифікувати облікові дані пароля для: Do you want to register a passkey for: - + Ви хочете зареєструвати пароль для: @@ -988,16 +1041,17 @@ Do you want to delete the entry? Register a new passkey to this entry: - + Зареєструвати новий пароль для цього запису: KeePassXC - Update passkey - + KeePassXC - Оновити пароль Entry already has a passkey. Do you want to overwrite the passkey in %1 - %2? - + Запис уже має пароль. +Ви хочете перезаписати пароль у %1 - %2? Register @@ -1022,10 +1076,6 @@ Do you want to overwrite the passkey in %1 - %2? General Загальні - - Browsers installed as snaps are currently not supported. - Наразі не підтримуються браузери, встановлені як Snap. - Enable integration for these browsers: Увімкнути інтеграцію з такими браузерами: @@ -1197,18 +1247,6 @@ Do you want to overwrite the passkey in %1 - %2? Custom extension ID Власний ідентифікатор розширення - - Due to Snap sandboxing, you must run a script to enable browser integration.<br />You can obtain this script from %1 - Через заходи безпеки у Snap, ви маєте запустити скрипт для увімкнення інтеграції з браузером.<br />Ви можете знайти цей скрипт у %1 - - - KeePassXC-Browser is needed for the browser integration to work. <br />Download it for %1 and %2 and %3. %4 - Щоб запрацювала інтеграція з браузером, потрібне розширення KeePassXC-Browser. <br />Завантажте його для %1, %2 та %3. %4 - - - Please see special instructions for browser extension use below - Нижче ви можете переглянути інструкцію для користування розширенням браузера - Executable Files Виконувані файли @@ -1251,10 +1289,18 @@ Do you want to overwrite the passkey in %1 - %2? Allows using insecure http://localhost with passkeys for testing purposes. - + Дозволяє використовувати небезпечний http://localhost з паролями для тестування. Allow using localhost with passkeys + Дозволити використовувати localhost з паролями + + + KeePassXC-Browser is needed for the browser integration to work. <br />Download it for %1 and %2 and %3. + KeePassXC-Browser потрібен для роботи інтеграції з браузером. <br />Завантажте його для %1 та %2 і %3. + + + Browsers installed using Snap or Flatpak are not supported with exception to Firefox installed using Snap. @@ -1399,6 +1445,20 @@ Do you want to overwrite the passkey in %1 - %2? Imported from CSV file: %1 Імпортовано з файлу CSV: %1 + + No Title Selected + Назва не вибрана + + + No title column was selected, entries will be hard to tell apart. +Are you sure you want to import? + Не вибрано стовпець з назвою, записи буде важко розрізнити. +Ви впевнені, що хочете імпортувати? + + + Tags + Мітки + CsvParserModel @@ -1462,6 +1522,14 @@ Backup database located at %2 Recycle Bin Смітник + + Database file read error. + + + + No file path was provided. + + DatabaseOpenDialog @@ -1610,14 +1678,6 @@ To prevent this error from appearing, you must go to "Database Settings / S <p>In addition to a password, you can use a secret file to enhance the security of your database. This file can be generated in your database's security settings.</p><p>This is <strong>not</strong> your *.kdbx database file!</p> <p>На додачу до пароля, ви можете використовувати секретний файл, щоб підвищити безпеку вашої бази даних. Цей файл можна створити у налаштуваннях безпеки вашої бази даних.</p><p>Це <strong>не</strong> ваш файл бази даних *.kdbx!</p> - - Click to add a key file. - Натисніть, щоб додати файл ключа. - - - <a href="#" style="text-decoration: underline">I have a key file</a> - <a href="#" style="text-decoration: underline">У мене є файл ключа</a> - Use hardware key [Serial: %1] Використовувати апаратний ключ [Серійний номер: %1] @@ -1654,6 +1714,18 @@ Are you sure you want to continue with this file?. Refresh Hardware Keys Оновити апаратні ключі + + Click to add a key file. + Натисніть, щоб додати файл ключа. + + + <a href="#" style="text-decoration: underline">I have a key file</a> + <a href="#" style="text-decoration: underline">У мене є файл ключа</a> + + + Hardware keys found, but no slots are configured. + Апаратні ключі знайдено, але жоден слот не налаштовано. + DatabaseSettingWidgetMetaData @@ -1688,6 +1760,22 @@ Are you sure you want to continue with this file?. Maintenance Обслуговування + + KeeShare + KeeShare + + + Secret Service Integration + Сполучення зі «Службою таємниць». + + + Remote Sync + Віддалена синхронізація + + + Database Settings: %1 + Параметри бази даних: %1 + DatabaseSettingsWidgetBrowser @@ -1858,14 +1946,14 @@ Are you sure you want to continue without a password? Weak password Слабкий пароль - - You must enter a stronger password to protect your database. - Вам потрібно ввести більш складний пароль, щоб захистити вашу базу даних. - This is a weak password! For better protection of your secrets, you should choose a stronger password. Це слабкий пароль! Для кращого захисту ваших секретів, вам слід обрати складніший пароль. + + The provided password does not meet the minimum quality requirement. + Наданий пароль не відповідає мінімальним вимогам до якості. + DatabaseSettingsWidgetEncryption @@ -2167,6 +2255,50 @@ removed from the database. Autosave delay since last change checkbox Прапорець затримки автозбереження з моменту останньої зміни + + Public Database Metadata + Публічні метадані бази даних + + + Warning: the following settings are not encrypted. + Увага: наступні налаштування не зашифровані. + + + Display name: + Відображуване ім'я: + + + Publically visible display name used on the unlock dialog + Публічне ім'я, що використовується в діалоговому вікні розблокування + + + Database public display name + Публічне ім'я бази даних + + + Display color: + Відображуваний колір: + + + Publically visible color used on the unlock dialog + Публічний колір, що використовується в діалоговому вікні розблокування + + + Database public display color chooser + Публічний колір бази даних + + + Clear + Очистити + + + Display icon: + Піктограма: + + + Select Database Icon + Вибрати піктограму бази даних + DatabaseSettingsWidgetKeeShare @@ -2262,6 +2394,139 @@ removed from the database. Поле опису бази даних + + DatabaseSettingsWidgetRemote + + Sync Commands + Синхронізація команд + + + Remove + Вилучити + + + Command Settings + Налаштування команд + + + Name + Назва + + + Save + Зберегти + + + Download + Завантажити + + + Command: + Команда: + + + Download command field + Поле команди завантаження + + + e.g.: "sftp user@hostname" or "scp user@hostname:DatabaseOnRemote.kdbx {TEMP_DATABASE}" + наприклад: "sftp user@hostname" або "scp user@hostname:DatabaseOnRemote.kdbx {TEMP_DATABASE}" + + + Input: + Введення: + + + Download input field + Поле введення завантаження + + + Upload + Завантажити + + + Upload command field + Поле команди завантаження + + + e.g.: "sftp user@hostname" or "scp {TEMP_DATABASE} user@hostname:DatabaseOnRemote.kdbx" + наприклад: "sftp user@hostname" або "scp {TEMP_DATABASE} user@hostname:DatabaseOnRemote.kdbx" + + + Upload input field + Поле команди вивантаження + + + Name cannot be empty. + Ім'я не може бути порожнім. + + + Test + Тест + + + Download command cannot be empty. + Команда завантаження не може бути порожньою. + + + Download failed with error: %1 + Помилка завантаження: %1 + + + Download finished, but file %1 could not be found. + Завантаження завершено, але файл %1 не вдалося знайти. + + + Download successful. + Успішне завантаження. + + + Save Remote Settings + Зберегти віддалені налаштування + + + You have unsaved changes. Do you want to save them? + У вас незбережені зміни. Хочете їх зберегти? + + + e.g.: +get DatabaseOnRemote.kdbx {TEMP_DATABASE} +exit +--- +{TEMP_DATABASE} is used as placeholder to store the database in a temporary location +The command has to exit. In case of `sftp` as last command `exit` has to be sent + + Наприклад: +отримати DatabaseOnRemote.kdbx {TEMP_DATABASE} +вийти +--- +{TEMP_DATABASE} використовується як заповнювач для зберігання бази даних у тимчасовому місці +Команда має вихід. У випадку з 'sftp' останньою командою має бути надіслано 'exit' + + + e.g.: +put {TEMP_DATABASE} DatabaseOnRemote.kdbx +exit +--- +{TEMP_DATABASE} is used as placeholder to store the database in a temporary location +The command has to exit. In case of `sftp` as last command `exit` has to be sent + + Наприклад: +put {TEMP_DATABASE} DatabaseOnRemote.kdbx +вийти +--- +{TEMP_DATABASE} використовується як заповнювач для зберігання бази даних у тимчасовому місці +Команда має вихід. У випадку з 'sftp' останньою командою має бути надіслано 'exit' + + + Timeout: + Таймаут: + + + seconds + секунд + + DatabaseTabWidget @@ -2335,6 +2600,11 @@ This is definitely a bug, please report it to the developers. Database tab name modifier %1 [Заблоковано] + + %1 [Temporary] + Database tab name modifier + %1 [Тимчасово] + DatabaseWidget @@ -2458,26 +2728,6 @@ Save changes? File has changed Файл було змінено - - The database file has changed. Do you want to load the changes? - Файл бази даних змінився. Завантажити зміни? - - - Merge Request - Запит на об'єднання - - - The database file has changed and you have unsaved changes. -Do you want to merge your changes? - Файл бази даних було змінено, у вас також є незбережені зміни. -Хочете об'єднати зміни? - - - Could not open the new database file while attempting to autoreload. -Error: %1 - Не вдалося відкрити новий файл бази даних під час автоматичного перезавантаження. -Помилка: %1 - Disable safe saves? Вимкнути безпечне збереження? @@ -2529,6 +2779,86 @@ Disable safe saves and try again? Database tab name modifier %1 [Нова база даних] + + Remote Sync did not contain any download or upload commands. + Віддалена синхронізація не містила жодних команд завантаження або вивантаження. + + + Remote sync '%1' completed successfully! + Віддалена синхронізація '%1' успішно завершена! + + + Remote sync '%1' failed: %2 + Не вдалося виконати віддалену синхронізацію '%1': %2 + + + Error while saving database %1: %2 + Помилка під час збереження бази даних %1: %2 + + + Downloading... + Завантаження... + + + Uploading... + Вивантаження... + + + Syncing... + Синхронізація... + + + Remove passkey from entry + Видалити пароль з запису + + + Do you want to remove the passkey from this entry? + Бажаєте видалити ключ доступу з цього запис? + + + The database file "%1" was modified externally + + + + Do you want to load the changes? + + + + Reload database + + + + Reloading database… + + + + Reload canceled + + + + Reload successful + + + + Reload pending user action… + + + + The database file "%1" was modified externally.<br>How would you like to proceed?<br><br>Merge all changes<br>Ignore the changes on disk until save<br>Discard unsaved changes + + + + The database file "%1" was modified externally.<br>How would you like to proceed?<br><br>Merge all changes then save<br>Overwrite the changes on disk<br>Discard unsaved changes + + + + Database file overwritten. + + + + Database file on disk cannot be unlocked with current credentials.<br>Enter new credentials and/or present hardware key to continue. + + EditEntryWidget @@ -2580,10 +2910,6 @@ Disable safe saves and try again? n/a н/д - - (encrypted) - (зашифровано) - Select private key Вибрати приватний ключ @@ -2686,6 +3012,10 @@ Would you like to correct it? %n year(s) %n рік%n роки%n років%n роки + + Failed to decrypt SSH key, ensure password is correct. + Не вдалося розшифрувати SSH-ключ, перевірте правильність пароля. + EditEntryWidgetAdvanced @@ -2857,18 +3187,10 @@ Would you like to correct it? Skip Auto-Submit for this entry Не надсилати автоматично дані цього запису - - Only send this setting to the browser for HTTP Auth dialogs. If enabled, normal login forms will not show this entry for selection. - Надсилати цей параметр до браузера лише в діалогах автентифікації HTTP. Якщо увімкнено, цей запис не пропонуватиметься для звичайних форм входу. - Use this entry only with HTTP Basic Auth Використовувати цей запис лише з HTTP Basic Auth - - Do not send this setting to the browser for HTTP Auth dialogs. If enabled, HTTP Auth dialogs will not show this entry for selection. - Не надсилати цей параметр до браузера в діалогах автентифікації HTTP. Якщо увімкнено, цей запис не пропонуватиметься для діалогів автентифікації HTTP. - Do not use this entry with HTTP Basic Auth Не використовувати цей запис для HTTP Basic Auth @@ -2887,11 +3209,19 @@ Would you like to correct it? These settings affect the entry's behaviour with the browser extension. - + Ці налаштування впливають на поведінку запису в розширенні браузера. Additional URLs - + Додаткові URL-адреси + + + Only send this entry to the browser for HTTP Auth dialogs. If enabled, normal login forms will not show this entry for selection. + Надсилайте цей запис браузеру лише для діалогів HTTP-аутентифікації. Якщо увімкнено, звичайні форми входу не показуватимуть цей запис для вибору. + + + Do not send this entry to the browser for HTTP Auth dialogs. If enabled, HTTP Auth dialogs will not show this entry for selection. + Не надсилайте цей параметр браузеру для діалогів HTTP-авторизації. Якщо увімкнено, діалоги HTTP-автентифікації не показуватимуть цей пункт для вибору. @@ -3115,6 +3445,10 @@ Would you like to correct it? seconds секунд + + Clear agent + + EditGroupWidget @@ -3557,6 +3891,24 @@ This may cause the affected plugins to malfunction. %1 - Clone %1 - Клон + + Passkey + Passkey + + + Invalid conversion type: %1 + Неприпустимий тип перетворення: %1 + + + Invalid conversion syntax: %1 + Неприпустимий синтаксис перетворення: %1 + + + Invalid regular expression syntax %1 +%2 + Неприпустимий синтаксис регулярного виразу %1 +%2 + EntryAttachments @@ -3565,6 +3917,21 @@ This may cause the affected plugins to malfunction. Неможливо відкрити файл "%1" + + EntryAttachmentsDialog + + Form + Форма + + + File name + + + + File contents... + + + EntryAttachmentsModel @@ -3602,14 +3969,6 @@ This may cause the affected plugins to malfunction. Remove Видалити - - Rename selected attachment - Перейменувати вибраний додаток - - - Rename - Перейменувати - Open selected attachment Відкрити вибраний додаток @@ -3727,6 +4086,18 @@ Would you like to overwrite the existing attachment? Вкладення "%1" вже існує. Хочете перезаписати наявне вкладення? + + New + + + + Preview + Попередній перегляд + + + Failed to preview an attachment: Attachment not found + + EntryAttributesModel @@ -3925,6 +4296,10 @@ Would you like to overwrite the existing attachment? Background Color Колір тла + + Group Path + + EntryPreviewWidget @@ -4320,6 +4695,14 @@ You can enable the DuckDuckGo website icon service in the security section of th Url URL-адреса + + Could not load key file. + Не вдалося завантажити файл ключа. + + + Could not open remote database. Password or key file may be incorrect. + Не вдалося відкрити віддалену базу даних. пароль або ключовий файл можуть бути неправильними. + ImportWizardPageSelect @@ -4423,6 +4806,50 @@ You can enable the DuckDuckGo website icon service in the security section of th KeePass1 Database База даних KeePass1 + + Proton Pass (.json) + + + + Proton Pass JSON Export + + + + Temporary Database + Тимчасова база даних + + + Command: + Команда: + + + e.g.: "sftp user@hostname" or "scp user@hostname:DatabaseOnRemote.kdbx {TEMP_DATABASE}" + наприклад: "sftp user@hostname" або "scp user@hostname:DatabaseOnRemote.kdbx {TEMP_DATABASE}" + + + Input: + Введення: + + + e.g.: +get DatabaseOnRemote.kdbx {TEMP_DATABASE} +exit +--- +{TEMP_DATABASE} is used as placeholder to store the database in a temporary location +The command has to exit. In case of `sftp` as last commend `exit` has to be sent + + Наприклад: +get DatabaseOnRemote.kdbx {TEMP_DATABASE} +exit +--- +{TEMP_DATABASE} використовується як заповнювач для зберігання бази даних у тимчасовому місці +Команда має завершитися. У випадку з 'sftp' останньою командою має бути надіслано 'exit' + + + + Remote Database (.kdbx) + Віддалена база даних (.kdbx) + KMessageWidget @@ -5508,7 +5935,7 @@ Are you sure you want to continue with this file? Show Menubar - + Показати рядок меню Show Toolbar @@ -5563,12 +5990,6 @@ This version is not meant for production use. Expect some bugs and minor issues, this version is meant for testing purposes. ПРИМІТКА: ви користуєтеся бета-версією KeePassXC. Можна помітити помилки чи незначні проблеми. Ця версія призначена лише для тестування. - - - WARNING: Your Qt version may cause KeePassXC to crash with an On-Screen Keyboard. -We recommend you use the AppImage available on our downloads page. - УВАГА: ваша версія Qt може спричиняти аварійне завершення роботи KeePassXC під час роботи з екранною клавіатурою. -Ми рекомендуємо використовувати AppImage, який ви можете отримати на нашій сторінці завантажень. No Tags @@ -5642,6 +6063,10 @@ We recommend you use the AppImage available on our downloads page. Import Passkey Імпорт Passkey + + Remote S&ync… + Віддалена с&инхронізація... + Quit Application Вийти з програми @@ -5746,6 +6171,10 @@ We recommend you use the AppImage available on our downloads page. Show Password Generator Генератор паролів + + Remove Passkey From Entry + Видалити пароль з запису + Perform Auto-Type: {USERNAME} Виконати автозаповнення: {USERNAME} @@ -5860,7 +6289,7 @@ We recommend you use the AppImage available on our downloads page. Toggle Show Menubar - + Перемикати показ рядка меню Toggle Show Toolbar @@ -5890,6 +6319,34 @@ We recommend you use the AppImage available on our downloads page. Toggle Allow Screen Capture Дозволити знімки екрану + + Show Group Panel + Показати панель груп + + + Toggle Show Group Panel + Відображати панель груп + + + Setup Remote Sync… + Налаштувати віддалену синхронізацію... + + + Password Generator + Генератор паролів + + + E&xpire Entry… + + + + Clear SSH Agent + + + + Clear all identities in ssh-agent + + ManageDatabase @@ -6040,6 +6497,25 @@ We recommend you use the AppImage available on our downloads page. Введіть назву та опис для своєї нової бази даних: + + NewEntryAttachmentsDialog + + Attachment name cannot be empty + + + + Attachment with the same name already exists + + + + Save attachment + Зберегти вкладення + + + New entry attachment + + + NixUtils @@ -6227,6 +6703,10 @@ We recommend you use the AppImage available on our downloads page. Unexpected EOF when writing private key Несподіваний кінець файлу під час запису таємного ключа + + (encrypted) + (зашифровано) + OpenSSHKeyGenDialog @@ -6275,7 +6755,7 @@ We recommend you use the AppImage available on our downloads page. Export the following passkey entries. - + Експортувати наступні записи паролів. @@ -6348,15 +6828,15 @@ Do you want to overwrite it? Import the following passkey: - + Імпортувати наступний пароль: Import the following passkey to this entry: - + Імпортувати наступний пароль до цього запису: Default passkeys group (Imported Passkeys) - + Група паролів за замовчуванням (Імпортовані паролі) @@ -6379,25 +6859,27 @@ Do you want to overwrite it? Open passkey file - + Відкрити файл пароля Cannot import passkey - + Не вдалося імпортувати пароль Cannot import passkey file "%1". Data is missing. - + Не вдалося імпортувати файл пароля "%1". Дані відсутні. Cannot import passkey file "%1". The following data is missing: %2 - + Не вдалося імпортувати файл пароля "%1". +Відсутні такі дані: +%2 Cannot import passkey file "%1". Private key is missing or malformed. - + Не вдалося імпортувати файл пароля "%1". Відсутній або пошкоджений приватний ключ. @@ -6578,10 +7060,6 @@ The following data is missing: Also choose from: Також вибирати з: - - Excluded characters: "0", "1", "l", "I", "O", "|", "﹒" - Виключені знаки: "0", "1", "l", "I", "O", "|", "﹒" - Exclude look-alike characters Виключити неоднозначні символи @@ -6606,10 +7084,6 @@ The following data is missing: Word Count: Кількість слів: - - Character Count: - Кількість символів: - Word Case: Регістр слів: @@ -6622,10 +7096,6 @@ The following data is missing: Add custom wordlist Додати власний список слів - - character - символ - Close Закрити @@ -6732,6 +7202,22 @@ Do you want to overwrite it? Special Characters Спеціальні символи + + passwordLength + Довжина пароля + + + Characters: %1 + Символи: %1 + + + MIXED case + Змішаний варіант + + + Excluded characters: "0", "1", "l", "I", "O", "|", "﹒", "B", "8", "G", "6" + Виключити символи: "0", "1", "l", "I", "O", "|", ".", "B", "8", "G", "6" + PasswordWidget @@ -6799,6 +7285,21 @@ Do you want to overwrite it? Натискайте &Tab між символами + + PreviewEntryAttachmentsDialog + + Preview entry attachment + + + + No preview available + + + + Image format not supported + + + QMessageBox @@ -7477,10 +7978,6 @@ Do you want to overwrite it? Invalid word count %1 Непридатна кількість слів %1 - - The word list is too small (< 1000 items) - Список слів надто малий (< 1000 одиниць) - Title for the entry. Заголовок запису. @@ -7625,10 +8122,6 @@ Do you want to overwrite it? Exit interactive mode. Вийти з діалогового режиму. - - Format to use when exporting. Available choices are 'xml' or 'csv'. Defaults to 'xml'. - Формат для експортування. Можливі формати: xml або csv. Типовий формат – xml. - Exports the content of a database to standard output in the specified format. Експортує вміст бази даних до стандартного виводу в зазначеному форматі. @@ -8217,18 +8710,6 @@ Kernel: %3 %4 file empty порожній файл - - malformed string - хибне рядкове значення - - - missing closing quote - бракує закривальних лапок - - - %1: (row, col) %2,%3 - %1: (рядок, позиція) %2,%3 - AES 256-bit AES 256-біт @@ -8472,11 +8953,12 @@ Kernel: %3 %4 Set the key file for the database. This option is deprecated, use --set-key-file instead. - + Встановіть файл ключа для бази даних. +Цю опцію застаріло, використовуйте замість цього --set-key-file. Databases have been locked. - + Бази даних були заблоковані. Attestation not supported @@ -8564,80 +9046,80 @@ This option is deprecated, use --set-key-file instead. Origin is empty or not allowed - + Походження порожнє або не дозволене Effective domain is not a valid domain - + Діючий домен є недійсним доменом Origin and RP ID do not match - + Походження та RP ID не збігаються No supported algorithms were provided - + Не було надано підтримуваних алгоритмів Wait for timer to expire - + Зачекайте, поки таймер завершиться Challenge is shorter than required minimum length - + Виклик коротший за необхідну мінімальну довжину. user.id does not match the required length - + user.id не відповідає необхідній довжині. Favorite Tag for favorite entries - + Вибране File does not exist. - + Файлу не існує. Cannot open file: %1 - + Не вдається відкрити файл: %1 Cannot parse file: %1 at position %2 - + Не вдалося розібрати файл: %1 на позиції %2 Failed to decrypt json file: %1 - + Не вдалося розшифрувати JSON-файл: %1 Invalid encKeyValidation field - + Недійсне поле encKeyValidation Invalid cipher list within encKeyValidation field - + Недійсний список шифрів у полі encKeyValidation Wrong password - + Неправильний пароль Invalid encrypted data field - + Недійсне зашифроване поле даних Invalid cipher list within encrypted data field - + Недійсний список шифрів у полі зашифрованих даних Cannot initialize cipher - + Не вдалося ініціалізувати шифр Cannot decrypt data - + Не вдалося розшифрувати дані Bitwarden Import @@ -8646,15 +9128,15 @@ This option is deprecated, use --set-key-file instead. Archived Tag for archived entries - + Архівовано Invalid 1PUX file format: Not a valid ZIP file. - + Недійсний формат файлу 1PUX: не є дійсним ZIP-файлом. Invalid 1PUX file format: Missing export.data - + Недійсний формат файлу 1PUX: відсутній файл export.data 1Password Import @@ -8673,13 +9155,89 @@ This option is deprecated, use --set-key-file instead. Скорочення - Unsupported KDF type, cannot decrypt json file + Unknown passkeys error + Невідома помилка паролів + + + Invalid KDF iterations, cannot decrypt json file + Недійсна кількість ітерацій KDF, не вдалося розшифрувати JSON-файл + + + Unsupported format, ensure your Bitwarden export is password-protected + Непідтримуваний формат, переконайтеся, що ваш експорт з Bitwarden захищений паролем. + + + Only PBKDF and Argon2 are supported, cannot decrypt json file + Підтримуються лише PBKDF та Argon2, не вдалося розшифрувати файл JSON. + + + Reset Shortcuts + Скинути ярлики + + + Double click an action to change its shortcut + Подвійний клік на дії, щоб змінити ярлик + + + Filter... + Фільтр... + + + Shortcut Conflict + Конфлікт ярликів + + + Shortcut %1 conflicts with '%2'. Overwrite shortcut? + Скорочення %1 конфліктує з '%2'. Перезаписати скорочення? + + + Cannot generate valid passphrases because the wordlist is too short + Не вдається згенерувати правильні парольні фрази, оскільки список слів занадто короткий + + + Encrypted files are not supported. - Unknown passkeys error + Proton Pass Import + + Delete plugin data? + Видалити дані модуля? + + + Delete plugin data from Entry(s)? + Видалити дані плагіна з запису?Видалити дані плагіна із записів?Видалити дані плагіна із запиів?Видалити дані плагіна із запису(ів)? + + + Passkey + Passkey + + + Format to use when exporting. Available choices are 'xml', 'csv' or 'html'. Defaults to 'xml'. + + + + start minimized to the system tray + + + + malformed string, possible unescaped delimiter + + + + missing closing delimiter + + + + %1, row: %2, column: %3 + + + + Tags + Мітки + QtIOCompressor @@ -8715,6 +9273,37 @@ This option is deprecated, use --set-key-file instead. Внутрішня помилка zlib: + + RemoteHandler + + Command `%1` did not finish in time. Process was killed. + Команда «%1» не виконала вчасно. Процес було завершено. + + + Failed to upload merged database. Command `%1` did not finish in time. Process was killed. + Не вдалося завантажити об'єднану базу даних. Команда `%1` не встигла виконатись. Процес було завершено. + + + Invalid download parameters provided. + Вказано неприпустимі параметри завантаження. + + + Command `%1` failed to download database. + Команді '%1' не вдалося завантажити базу даних. + + + Invalid database pointer or upload parameters provided. + Хибний вказівник на базу даних або параметри завантаження. + + + Command `%1` exited with status code: %2 + Команду '%1' завершено з кодом стану: %2 + + + Failed to upload merged database. Command `%1` exited with status code: %2 + Не вдалося завантажити об'єднану базу даних. Команда `%1` завершилася з кодом стану: %2 + + ReportsWidgetBrowserStatistics @@ -8781,6 +9370,10 @@ This option is deprecated, use --set-key-file instead. Exclude from reports Виключити зі звітів + + Expire Entry(s)… + + Only show entries that have a URL Показати тільки записи, що містять URL @@ -8797,36 +9390,33 @@ This option is deprecated, use --set-key-file instead. (Expired) (Протерміновано) + + Delete plugin data from Entry(s)… + Видалити дані плагіна з запису?Видалити дані плагіна з записів?Видалити дані плагіна з записів?Видалити дані плагіна із запису(ів)? + ReportsWidgetHealthcheck - Hover over reason to show additional details. Double-click entries to edit. - Наведіть курсор на причину, щоб переглянути додаткові відомості. Клацніть двічі по запису для його редагування. + Show expired entries + Показати прострочені записи - Bad - Password quality - Погана + (Expired) + (Протерміновано) + + + Hover over reason to show additional details. Double-click entries to edit. + Наведіть курсор на причину, щоб переглянути додаткові відомості. Клацніть двічі по запису для його редагування. Bad — password must be changed Погана – пароль необхідно змінити - - Poor - Password quality - Погана - Poor — password should be changed Погана – пароль слід змінити - - Weak - Password quality - Слабка - Weak — consider changing the password Слабка – розгляньте можливість змінити пароль @@ -8875,18 +9465,14 @@ This option is deprecated, use --set-key-file instead. Exclude from reports Виключити зі звітів - - Show expired entries - Показати прострочені записи + + Expire Entry(s)… + Show entries that have been excluded from reports Показати записи, які було виключено зі звітів - - (Expired) - (Протерміновано) - ReportsWidgetHibp @@ -8982,6 +9568,10 @@ This option is deprecated, use --set-key-file instead. Exclude from reports Виключити зі звітів + + Expire Entry(s)… + + ReportsWidgetPasskeys @@ -9039,15 +9629,15 @@ This option is deprecated, use --set-key-file instead. The passkey file will be vulnerable to theft and unauthorized use, if left unsecured. Are you sure you want to continue? - + Файл пароля буде вразливим до крадіжки та несанкціонованого використання, якщо залишити його незахищеним. Ви впевнені, що хочете продовжити? Please wait, list of entries with passkeys is being updated… - + Будь ласка, зачекайте, список записів з паролями оновлюється… No entries with passkeys. - + Немає записів з паролями. @@ -9223,6 +9813,14 @@ This option is deprecated, use --set-key-file instead. No agent running, cannot list identities. Немає запущеного посередника, неможливо відобразити перелік ключів. + + Failed to remove all SSH identities from agent. + + + + All SSH identities removed from agent. + + SearchHelpWidget @@ -9397,11 +9995,11 @@ This option is deprecated, use --set-key-file instead. <html><head/><body><p>This setting does not override disabling recycle bin prompts </p></body></html> - + <html><head/><body><p>Це налаштування не перекриває вимкнення підказок кошика для сміття </p></body></html> <html><head/><body><p>This improves compatibility with certain applications which search for password without unlocking the database first.</p><p>But enabling this may also crash the client if the database can not be unlocked within a certain timeout. (Usually 25s, but may be a different value set in applications.) </p></body></html> - + <html><head/><body><p>Це покращує сумісність з певними додатками, які шукають пароль без попереднього розблокування бази даних.</p><p>Але увімкнення цього може також призвести до збою клієнта, якщо базу даних не вдалося розблокувати протягом певного часу (зазвичай 25 секунд, але може бути інше значення, встановлене в додатках)</p></body></html> @@ -9508,29 +10106,6 @@ This option is deprecated, use --set-key-file instead. Експортування до %1 - - ShortcutSettingsWidget - - Double click an action to change its shortcut - Подвійний клік на дії, щоб змінити ярлик - - - Shortcut Conflict - Конфлікт ярликів - - - Filter... - Фільтр... - - - Shortcut %1 conflicts with '%2'. Overwrite shortcut? - Скорочення %1 конфліктує з '%2'. Перезаписати скорочення? - - - Reset Shortcuts - Скинути ярлики - - TagModel @@ -9748,7 +10323,7 @@ Example: JBSWY3DPEHPK3PXP Import File - + Імпортувати файл @@ -9820,12 +10395,16 @@ Example: JBSWY3DPEHPK3PXP Апаратних ключів не виявлено - <p>If you own a <a href="https://www.yubico.com/">YubiKey</a> or <a href="https://onlykey.io">OnlyKey</a>, you can use it for additional security.</p><p>The key requires one of its slots to be programmed as <a href="https://docs.yubico.com/yesdk/users-manual/application-otp/challenge-response.html">HMAC-SHA1 Challenge-Response</a>.</p> - + Refresh hardware keys + Оновити апаратні ключі - Refresh hardware keys - + <p>If you own a <a href="https://www.yubico.com/">YubiKey</a> or <a href="https://onlykey.io">OnlyKey</a>, you can use it for additional security.</p><p>The key requires one of its slots to be programmed with <a href="https://keepassxc.org/docs/#faq-yubikey-howto">Challenge-Response</a>.</p> + <p>Якщо у вас є <a href="https://www.yubico.com/">YubiKey</a> або <a href="https://onlykey.io">OnlyKey</a>, ви можете використовувати його для додаткової безпеки.</p><p>Для ключа потрібно, щоб один із його слотів був запрограмований на <a href="https://KeePassXC.org/docs/#faq-yubikey-howto">виклик-відповідь</a>.</p> + + + Hardware keys found, but no slots are configured + Апаратні ключі знайдено, але жоден слот не налаштовано. diff --git a/share/translations/keepassxc_zh_CN.ts b/share/translations/keepassxc_zh_CN.ts index 02921a6b9..bc457df0a 100644 --- a/share/translations/keepassxc_zh_CN.ts +++ b/share/translations/keepassxc_zh_CN.ts @@ -217,18 +217,50 @@ You must restart the application to set the new language. Would you like to restart now? 您必须重新启动应用才能应用新语言。要现在重新启动吗? - - Reset Settings? - 重置选项? - - - Are you sure you want to reset all general and security settings to default? - 您确定要将所有常规和安全设置重置为默认值吗? - Select backup storage directory 选择备份存储文件夹 + + Confirm Reset + 确认重置 + + + Are you sure you want to reset all settings to default? + 您确定要将所有设置重置为默认值吗? + + + Import KeePassXC Settings + 导入 KeePassXC 设置 + + + Failed to import settings from %1, not a valid settings file. + 从 %1 导入设置失败,不是有效的设置文件。 + + + Export KeePassXC Settings + 导出 KeePassXC 设置 + + + Small + + + + Normal + 正常 + + + Medium + + + + Large + + + + Custom + 自定义 + ApplicationSettingsWidgetGeneral @@ -280,25 +312,6 @@ Include beta releases when checking for updates 检查更新时包含 Beta 版本 - - On database unlock, show entries that - 解锁数据库时,显示符合条件的条目 - - - have expired - On database unlock, show entries that... - 已过期 - - - days - On database unlock, show entries that will expire within %1 days - 天内过期 - - - will expire within - On database unlock, show entries that... - 将在 - File Management 文件管理 @@ -323,22 +336,10 @@ Backup database file before saving 保存前备份数据库文件 - - Backup destination - 备份目的地 - - - Specifies the database backup file location. Occurrences of "{DB_FILENAME}" are replaced with the filename of the saved database without extension. {TIME:<format>} is replaced with the backup time, see https://doc.qt.io/qt-5/qdatetime.html#toString. <format> defaults to format string "dd_MM_yyyy_hh-mm-ss". - 指定数据库备份文件位置,其中 "{DB_FILENAME}" 会被替换为保存的数据库文件名,不包含扩展名。{TIME:<format>} 会被替换为备份时间,详见 https://doc.qt.io/qt-5/qdatetime.html#toString 。<format> 默认为格式字符串 "dd_MM_yyyy_hh-mm-ss"。 - {DB_FILENAME}.old.kdbx {DB_FILENAME}.old.kdbx - - Choose... - 选择... - Use alternative saving method (may solve problems with Dropbox, Google Drive, GVFS, etc.) 使用替代保存方式(可能会解决 Dropbox、Google Drive、GVFS 等问题) @@ -505,6 +506,71 @@ Remember last typed entry for: 记住上次输入的条目: + + On database unlock, show entries that will expire within + 解锁数据库时,显示即将过期的条目 + + + On database unlock, show entries that will expire within + 解锁数据库时,显示即将过期的条目 + + + days + number of days warning for password expiration + 天内过期 + + + Destination format: + 目标格式: + + + <html><head/><body><p><span style=" font-weight:600;">{DB_FILENAME}</span> is replaced with the filename of the saved database without extension</p><p><span style=" font-weight:600;">{TIME:&lt;format&gt;}</span> is replaced with the specified time format (default: dd_MM_yyyy_hh-mm-ss)</p><p>See the User Guide for more details</p></body></html> + <html><head/><body><p><span style=" font-weight:600;">{DB_FILENAME}</span> 将被替换为保存数据库的文件名,不含扩展名</p><p><span style=" font-weight:600;">{TIME:&lt;format&gt;}</span> 将被替换为指定的时间格式(默认:dd_MM_yyyy_hh-mm-ss)</p><p>查看用户指南了解详情</p></body></html> + + + Choose folder... + 选择文件夹... + + + Show confirmation before moving entries to recycle bin + 删除条目到回收站之前提示确认 + + + Copy data on double clicking field in entry view + 在条目视图中,双击字段复制数据 + + + Show toolbar + 显示工具栏 + + + Show the menu bar by pressing the Alt key + 按下 Alt 键显示菜单栏 + + + Show menubar + 显示菜单栏 + + + Import settings… + 导入设置… + + + Export settings… + 导出设置… + + + Open browser on double clicking URL field in entry view + 在条目视图中,双击 URL 字段打开浏览器 + + + Font size: + 字体大小: + + + Font size selection + 字体大小选择 + ApplicationSettingsWidgetSecurity @@ -570,18 +636,6 @@ Hide passwords in the entry preview panel 在条目预览面板中隐藏密码 - - Hide entry notes by default - 默认情况下隐藏条目备注 - - - Move entries to recycle bin without confirmation - 删除到回收站无需确认 - - - Enable double click to copy the username/password entry columns - 启用双击复制条目的用户名/密码列 - Privacy 隐私 @@ -594,6 +648,18 @@ Hide TOTP in the entry preview panel 在条目预览面板隐藏 TOTP + + Lock databases when switching user + 切换用户时锁定数据库 + + + Lock Options + 锁定选项 + + + Hide notes in the entry preview panel + 在条目预览面板隐藏备注 + AutoType @@ -641,20 +707,6 @@ Entry does not have attribute for PICKCHARS: %1 条目不包含用于 PICKCHARS 的属性:%1 - - Invalid conversion type: %1 - 无效的转换类型:%1 - - - Invalid conversion syntax: %1 - 无效的转换语法:%1 - - - Invalid regular expression syntax %1 -%2 - 无效的正则表达式语法 %1 -%2 - Invalid placeholder: %1 无效的占位符:%1 @@ -886,24 +938,25 @@ Please select the correct database for saving credentials. Add to existing entry - + 添加到现有条目 Existing passkey found. Do you want to register a new passkey for: - + 找到已存在的通行密钥。 +您是否要注册新通行密钥到: Select the existing passkey and press Update to replace it. - + 选择已存在的通行密钥并按下更新来替换。 Authenticate passkey credentials for: - + 认证通行密钥凭据: Do you want to register a passkey for: - + 您是否要注册通行密钥到: @@ -988,16 +1041,17 @@ Do you want to delete the entry? Register a new passkey to this entry: - + 注册新通行密钥到此条目: KeePassXC - Update passkey - + KeePassXC - 更新通行密钥 Entry already has a passkey. Do you want to overwrite the passkey in %1 - %2? - + 条目已有一个通行密钥。 +您想要覆盖 %1 - %2 中的通行密钥吗? Register @@ -1022,10 +1076,6 @@ Do you want to overwrite the passkey in %1 - %2? General 常规 - - Browsers installed as snaps are currently not supported. - 以 Snap 软件包形式安装的浏览器目前不受支持。 - Enable integration for these browsers: 为这些浏览器开启集成: @@ -1197,18 +1247,6 @@ Do you want to overwrite the passkey in %1 - %2? Custom extension ID 自定义扩展 ID - - Due to Snap sandboxing, you must run a script to enable browser integration.<br />You can obtain this script from %1 - 由于 Snap 沙盒限制,您必须运行一个脚本才能启用浏览器集成。<br />您可以从 %1 获取此脚本 - - - KeePassXC-Browser is needed for the browser integration to work. <br />Download it for %1 and %2 and %3. %4 - 要启用浏览器集成,您必须安装 KeePassXC-Browser。<br />下载适用于 %1、%2 和 %3 的版本。%4 - - - Please see special instructions for browser extension use below - 请参阅下面的浏览器扩展使用特殊说明 - Executable Files 可执行文件 @@ -1251,11 +1289,19 @@ Do you want to overwrite the passkey in %1 - %2? Allows using insecure http://localhost with passkeys for testing purposes. - + 允许通行密钥使用不安全的 http://localhost 用于测试目的。 Allow using localhost with passkeys - + 允许通行密钥使用 localhost + + + KeePassXC-Browser is needed for the browser integration to work. <br />Download it for %1 and %2 and %3. + 要启用浏览器集成,您必须安装 KeePassXC-Browser。<br />下载适用于 %1、%2 和 %3 的版本。 + + + Browsers installed using Snap or Flatpak are not supported with exception to Firefox installed using Snap. + 通过 Snap 或 Flatpak 安装的浏览器不受支持,但通过 Snap 安装的 Firefox 除外。 @@ -1399,6 +1445,20 @@ Do you want to overwrite the passkey in %1 - %2? Imported from CSV file: %1 已从 CSV 文件导入:%1 + + No Title Selected + 未选择标题 + + + No title column was selected, entries will be hard to tell apart. +Are you sure you want to import? + 未选择标题列,条目将难以区分。 +您确定要导入吗? + + + Tags + 标签 + CsvParserModel @@ -1462,6 +1522,14 @@ Backup database located at %2 Recycle Bin 回收站 + + Database file read error. + 数据库文件读取错误。 + + + No file path was provided. + 未提供文件路径。 + DatabaseOpenDialog @@ -1610,14 +1678,6 @@ To prevent this error from appearing, you must go to "Database Settings / S <p>In addition to a password, you can use a secret file to enhance the security of your database. This file can be generated in your database's security settings.</p><p>This is <strong>not</strong> your *.kdbx database file!</p> <p>除了密码之外,您还可以使用机密文件来增强数据库的安全性。此文件可以在数据库的安全设置中生成。</p><p>这<strong>不是</strong>您的 *.kdbx 数据库文件!</p> - - Click to add a key file. - 点击以添加密钥文件。 - - - <a href="#" style="text-decoration: underline">I have a key file</a> - <a href="#" style="text-decoration: underline">我有一份密钥文件</a> - Use hardware key [Serial: %1] 使用硬件密钥 [序号:%1] @@ -1654,6 +1714,18 @@ Are you sure you want to continue with this file?. Refresh Hardware Keys 刷新硬件密钥 + + Click to add a key file. + 点击以添加密钥文件。 + + + <a href="#" style="text-decoration: underline">I have a key file</a> + <a href="#" style="text-decoration: underline">我有一份密钥文件</a> + + + Hardware keys found, but no slots are configured. + 硬件密钥已找到,但未配置任何插槽。 + DatabaseSettingWidgetMetaData @@ -1688,6 +1760,22 @@ Are you sure you want to continue with this file?. Maintenance 维护 + + KeeShare + KeeShare + + + Secret Service Integration + 保密服务集成 + + + Remote Sync + 远程同步 + + + Database Settings: %1 + 数据库设置:%1 + DatabaseSettingsWidgetBrowser @@ -1858,14 +1946,14 @@ Are you sure you want to continue without a password? Weak password 较弱密码 - - You must enter a stronger password to protect your database. - 您必须输入更强的密码来保护数据库。 - This is a weak password! For better protection of your secrets, you should choose a stronger password. 这是一个弱密码!为了更好地保护您的秘密,您应该选择更强的密码。 + + The provided password does not meet the minimum quality requirement. + 提供的密码未达到最低强度要求。 + DatabaseSettingsWidgetEncryption @@ -2167,6 +2255,50 @@ removed from the database. Autosave delay since last change checkbox 修改后自动保存延迟复选框 + + Public Database Metadata + 公开数据库元数据 + + + Warning: the following settings are not encrypted. + 警告:下列设置未被加密。 + + + Display name: + 显示名称: + + + Publically visible display name used on the unlock dialog + 在解锁对话框中公开显示的名称 + + + Database public display name + 数据库公开显示名称 + + + Display color: + 显示颜色: + + + Publically visible color used on the unlock dialog + 在解锁对话框中公开可见的颜色 + + + Database public display color chooser + 数据库公开显示颜色选择器 + + + Clear + 清空 + + + Display icon: + 显示图标: + + + Select Database Icon + 选择数据库图标 + DatabaseSettingsWidgetKeeShare @@ -2262,6 +2394,141 @@ removed from the database. 数据库描述字段 + + DatabaseSettingsWidgetRemote + + Sync Commands + 同步命令 + + + Remove + 删除 + + + Command Settings + 命令设置 + + + Name + 名称 + + + Save + 保存 + + + Download + 下载 + + + Command: + 命令: + + + Download command field + 下载命令字段 + + + e.g.: "sftp user@hostname" or "scp user@hostname:DatabaseOnRemote.kdbx {TEMP_DATABASE}" + 示例:“sftp user@hostname”或“scp user@hostname:DatabaseOnRemote.kdbx {TEMP_DATABASE}” + + + Input: + 输入: + + + Download input field + 下载输入字段 + + + Upload + 上传 + + + Upload command field + 上传命令字段 + + + e.g.: "sftp user@hostname" or "scp {TEMP_DATABASE} user@hostname:DatabaseOnRemote.kdbx" + 示例:“sftp user@hostname”或“scp {TEMP_DATABASE} user@hostname:DatabaseOnRemote.kdbx” + + + Upload input field + 上传输入字段 + + + Name cannot be empty. + 名称不能为空。 + + + Test + 测试 + + + Download command cannot be empty. + 下载命令不能为空。 + + + Download failed with error: %1 + 下载失败,错误为:%1 + + + Download finished, but file %1 could not be found. + 下载完成,但无法找到文件 %1。 + + + Download successful. + 下载成功。 + + + Save Remote Settings + 保存远程设置 + + + You have unsaved changes. Do you want to save them? + 您有未保存的更改。要保存它们吗? + + + e.g.: +get DatabaseOnRemote.kdbx {TEMP_DATABASE} +exit +--- +{TEMP_DATABASE} is used as placeholder to store the database in a temporary location +The command has to exit. In case of `sftp` as last command `exit` has to be sent + + 示例: +get DatabaseOnRemote.kdbx {TEMP_DATABASE} +exit +--- +{TEMP_DATABASE} 作为占位符,表示存储数据库的临时位置 +命令必须可以退出。如果最后一个命令是 `sftp` 则必须发送 `exit` 命令 + + + + e.g.: +put {TEMP_DATABASE} DatabaseOnRemote.kdbx +exit +--- +{TEMP_DATABASE} is used as placeholder to store the database in a temporary location +The command has to exit. In case of `sftp` as last command `exit` has to be sent + + 示例: +put {TEMP_DATABASE} DatabaseOnRemote.kdbx +exit +--- +{TEMP_DATABASE} 作为占位符,表示存储数据库的临时位置 +命令必须可以退出。如果最后一个命令是 `sftp` 则必须发送 `exit` 命令 + + + + Timeout: + 超时: + + + seconds + + + DatabaseTabWidget @@ -2335,6 +2602,11 @@ This is definitely a bug, please report it to the developers. Database tab name modifier %1 [锁定] + + %1 [Temporary] + Database tab name modifier + %1 [临时] + DatabaseWidget @@ -2458,26 +2730,6 @@ Save changes? File has changed 文件已变更 - - The database file has changed. Do you want to load the changes? - 数据库文件已发生变化。是否重新载入? - - - Merge Request - 合并请求 - - - The database file has changed and you have unsaved changes. -Do you want to merge your changes? - 数据库文件已发生变化,并且您有未保存的更改。 -您想合并您的修改吗? - - - Could not open the new database file while attempting to autoreload. -Error: %1 - 尝试自动重载时无法打开新的数据库文件。 -错误:%1 - Disable safe saves? 禁用安全保存? @@ -2529,6 +2781,86 @@ Disable safe saves and try again? Database tab name modifier %1 [新建数据库] + + Remote Sync did not contain any download or upload commands. + 远程同步未包含任何下载或上传命令。 + + + Remote sync '%1' completed successfully! + 远程同步“%1”成功完成! + + + Remote sync '%1' failed: %2 + 远程同步“%1”失败:%2 + + + Error while saving database %1: %2 + 保存数据库 %1 时出错:%2 + + + Downloading... + 正在下载... + + + Uploading... + 正在上传... + + + Syncing... + 正在同步... + + + Remove passkey from entry + 从条目内移除通行密钥 + + + Do you want to remove the passkey from this entry? + 是否从此条目中移除通行密钥? + + + The database file "%1" was modified externally + 数据库文件“%1”被外部修改 + + + Do you want to load the changes? + 您要加载这些变更吗? + + + Reload database + 重新加载数据库 + + + Reloading database… + 正在重新加载数据库… + + + Reload canceled + 重新加载已取消 + + + Reload successful + 重新加载成功 + + + Reload pending user action… + 重新加载正在等待用户操作… + + + The database file "%1" was modified externally.<br>How would you like to proceed?<br><br>Merge all changes<br>Ignore the changes on disk until save<br>Discard unsaved changes + 数据库文件“%1”被外部修改。<br>您想要怎样操作?<br><br>合并所有变更<br>在保存之前忽略磁盘上的变更<br>放弃未保存的变更 + + + The database file "%1" was modified externally.<br>How would you like to proceed?<br><br>Merge all changes then save<br>Overwrite the changes on disk<br>Discard unsaved changes + 数据库文件“%1”被外部修改。<br>您想要怎样操作?<br><br>合并所有变更并保存<br>覆盖磁盘上的变更<br>放弃未保存的变更 + + + Database file overwritten. + 数据库文件已覆盖。 + + + Database file on disk cannot be unlocked with current credentials.<br>Enter new credentials and/or present hardware key to continue. + 磁盘上的数据库文件无法被当前凭据解锁。<br>输入新凭据并/或提供硬件密钥以继续。 + EditEntryWidget @@ -2580,10 +2912,6 @@ Disable safe saves and try again? n/a - - (encrypted) - (已加密) - Select private key 选择私钥文件 @@ -2686,6 +3014,10 @@ Would you like to correct it? %n year(s) %n 年 + + Failed to decrypt SSH key, ensure password is correct. + 解密 SSH 密钥失败,请确认密码是否正确。 + EditEntryWidgetAdvanced @@ -2857,18 +3189,10 @@ Would you like to correct it? Skip Auto-Submit for this entry 跳过此条目的自动提交 - - Only send this setting to the browser for HTTP Auth dialogs. If enabled, normal login forms will not show this entry for selection. - 仅将此设置发送到浏览器的 HTTP 认证对话框。启用后,普通登录表单不会再显示此条目供选择。 - Use this entry only with HTTP Basic Auth 此条目仅用于 HTTP Basic 认证 - - Do not send this setting to the browser for HTTP Auth dialogs. If enabled, HTTP Auth dialogs will not show this entry for selection. - 不要将此设置发送到浏览器的 HTTP 认证对话框。启用后,HTTP 认证对话框不会再显示此条目供选择。 - Do not use this entry with HTTP Basic Auth 此条目不用于 HTTP Basic 认证 @@ -2893,6 +3217,14 @@ Would you like to correct it? Additional URLs 附加 URL + + Only send this entry to the browser for HTTP Auth dialogs. If enabled, normal login forms will not show this entry for selection. + 仅将此条目发送到浏览器的 HTTP 认证对话框。启用后,普通登录表单不会再显示此条目供选择。 + + + Do not send this entry to the browser for HTTP Auth dialogs. If enabled, HTTP Auth dialogs will not show this entry for selection. + 不要将此条目发送到浏览器的 HTTP 认证对话框。启用后,HTTP 认证对话框不会再显示此条目供选择。 + EditEntryWidgetHistory @@ -3115,6 +3447,10 @@ Would you like to correct it? seconds + + Clear agent + 清除代理 + EditGroupWidget @@ -3557,6 +3893,24 @@ This may cause the affected plugins to malfunction. %1 - Clone %1 - 副本 + + Passkey + 通行密钥 + + + Invalid conversion type: %1 + 无效的转换类型:%1 + + + Invalid conversion syntax: %1 + 无效的转换语法:%1 + + + Invalid regular expression syntax %1 +%2 + 无效的正则表达式语法 %1 +%2 + EntryAttachments @@ -3565,6 +3919,21 @@ This may cause the affected plugins to malfunction. 无法打开文件“%1” + + EntryAttachmentsDialog + + Form + 表单 + + + File name + 文件名 + + + File contents... + 文件内容… + + EntryAttachmentsModel @@ -3602,14 +3971,6 @@ This may cause the affected plugins to malfunction. Remove 删除 - - Rename selected attachment - 重命名所选附件 - - - Rename - 重命名 - Open selected attachment 打开所选附件 @@ -3723,6 +4084,18 @@ Would you like to overwrite the existing attachment? 附件“%1”已存在。 您要覆盖已存在的附件吗? + + New + 新建 + + + Preview + 预览 + + + Failed to preview an attachment: Attachment not found + 预览附件失败:未找到附件 + EntryAttributesModel @@ -3921,6 +4294,10 @@ Would you like to overwrite the existing attachment? Background Color 背景色 + + Group Path + 群组路径 + EntryPreviewWidget @@ -4316,6 +4693,14 @@ You can enable the DuckDuckGo website icon service in the security section of th Url URL + + Could not load key file. + 无法加载密钥文件。 + + + Could not open remote database. Password or key file may be incorrect. + 无法打开远程数据库。密码或密钥文件可能不正确。 + ImportWizardPageSelect @@ -4419,6 +4804,50 @@ You can enable the DuckDuckGo website icon service in the security section of th KeePass1 Database KeePass1 数据库 + + Proton Pass (.json) + Proton Pass (.json) + + + Proton Pass JSON Export + Proton Pass JSON 导出 + + + Temporary Database + 临时数据库 + + + Command: + 命令: + + + e.g.: "sftp user@hostname" or "scp user@hostname:DatabaseOnRemote.kdbx {TEMP_DATABASE}" + 示例:“sftp user@hostname”或“scp user@hostname:DatabaseOnRemote.kdbx {TEMP_DATABASE}” + + + Input: + 输入: + + + e.g.: +get DatabaseOnRemote.kdbx {TEMP_DATABASE} +exit +--- +{TEMP_DATABASE} is used as placeholder to store the database in a temporary location +The command has to exit. In case of `sftp` as last commend `exit` has to be sent + + 示例: +get DatabaseOnRemote.kdbx {TEMP_DATABASE} +exit +--- +{TEMP_DATABASE} 作为占位符,表示存储数据库的临时位置 +命令必须可以退出。如果最后一个命令是 `sftp` 则必须发送 `exit` 命令 + + + + Remote Database (.kdbx) + 远程数据库(.kdbx) + KMessageWidget @@ -5559,11 +5988,6 @@ Expect some bugs and minor issues, this version is meant for testing purposes.注意:您使用的是 KeePassXC 的预发布版本。 可能会有一些错误和小问题,此版本仅供测试目的使用。 - - WARNING: Your Qt version may cause KeePassXC to crash with an On-Screen Keyboard. -We recommend you use the AppImage available on our downloads page. - 警告:您的 Qt 版本可能会导致 KeePassXC 在使用屏幕键盘时崩溃。我们建议您使用我们的下载页面上提供的 AppImage。 - No Tags 无标签 @@ -5636,6 +6060,10 @@ We recommend you use the AppImage available on our downloads page. Import Passkey 导入通行密钥 + + Remote S&ync… + 远程同步(&Y)… + Quit Application 退出应用 @@ -5740,6 +6168,10 @@ We recommend you use the AppImage available on our downloads page. Show Password Generator 显示密码生成器 + + Remove Passkey From Entry + 从条目内移除通行密钥 + Perform Auto-Type: {USERNAME} 执行自动输入:{USERNAME} @@ -5884,6 +6316,34 @@ We recommend you use the AppImage available on our downloads page. Toggle Allow Screen Capture 切换允许屏幕截图 + + Show Group Panel + 显示群组面板 + + + Toggle Show Group Panel + 切换显示群组面板 + + + Setup Remote Sync… + 设置远程同步… + + + Password Generator + 密码生成器 + + + E&xpire Entry… + 过期条目(&X)… + + + Clear SSH Agent + 清除 SSH 代理 + + + Clear all identities in ssh-agent + 清除 ssh-agent 内的所有身份 + ManageDatabase @@ -6034,6 +6494,25 @@ We recommend you use the AppImage available on our downloads page. 请填写新数据库的名称和可选的说明: + + NewEntryAttachmentsDialog + + Attachment name cannot be empty + 附件名称不能为空 + + + Attachment with the same name already exists + 同名附件已存在 + + + Save attachment + 保存附件 + + + New entry attachment + 新建条目附件 + + NixUtils @@ -6221,6 +6700,10 @@ We recommend you use the AppImage available on our downloads page. Unexpected EOF when writing private key 写入私钥时遇到意外的 EOF + + (encrypted) + (已加密) + OpenSSHKeyGenDialog @@ -6269,7 +6752,7 @@ We recommend you use the AppImage available on our downloads page. Export the following passkey entries. - + 导出以下通行密钥条目。 @@ -6343,15 +6826,15 @@ Do you want to overwrite it? Import the following passkey: - + 导入以下通行密钥: Import the following passkey to this entry: - + 导入以下通行密钥到此条目: Default passkeys group (Imported Passkeys) - + 默认通行密钥群组(导入的通行密钥) @@ -6374,25 +6857,27 @@ Do you want to overwrite it? Open passkey file - + 打开通行密钥文件 Cannot import passkey - + 无法导入通行密钥 Cannot import passkey file "%1". Data is missing. - + 无法导入通行密钥文件“%1”。数据缺失。 Cannot import passkey file "%1". The following data is missing: %2 - + 无法导入通行密钥文件“%1”。 +以下数据缺失: +%2 Cannot import passkey file "%1". Private key is missing or malformed. - + 无法导入通行密钥文件“%1”。私钥缺失或损坏。 @@ -6573,10 +7058,6 @@ The following data is missing: Also choose from: 也在此选择: - - Excluded characters: "0", "1", "l", "I", "O", "|", "﹒" - 排除字符:“0”、“1”、“l”、“I”、“O”、“|”、“﹒” - Exclude look-alike characters 排除相似的字符 @@ -6601,10 +7082,6 @@ The following data is missing: Word Count: 词数: - - Character Count: - 字符数: - Word Case: 字符大小写: @@ -6617,10 +7094,6 @@ The following data is missing: Add custom wordlist 添加自定义词表 - - character - 字符 - Close 关闭 @@ -6727,6 +7200,22 @@ Do you want to overwrite it? Special Characters 特殊字符 + + passwordLength + 密码长度 + + + Characters: %1 + 字符:%1 + + + MIXED case + 大小写混合 + + + Excluded characters: "0", "1", "l", "I", "O", "|", "﹒", "B", "8", "G", "6" + 排除字符:“0”、“1”、“l”、“I”、“O”、“|”、“﹒”、“B”、“8”、“G”、“6” + PasswordWidget @@ -6794,6 +7283,21 @@ Do you want to overwrite it? 在字符之间按 &Tab 键 + + PreviewEntryAttachmentsDialog + + Preview entry attachment + 预览条目附件 + + + No preview available + 预览不可用 + + + Image format not supported + 图像格式不支持 + + QMessageBox @@ -7472,10 +7976,6 @@ Do you want to overwrite it? Invalid word count %1 无效的词数 %1 - - The word list is too small (< 1000 items) - 词表太小(少于 1000 项) - Title for the entry. 条目的标题。 @@ -7620,10 +8120,6 @@ Do you want to overwrite it? Exit interactive mode. 退出交互模式。 - - Format to use when exporting. Available choices are 'xml' or 'csv'. Defaults to 'xml'. - 导出时使用的格式。可用的选项是“xml”或“csv”。默认值为“xml”。 - Exports the content of a database to standard output in the specified format. 将数据库内容按照指定的格式输出至标准输出。 @@ -8210,18 +8706,6 @@ CPU 架构:%2 file empty 文件为空 - - malformed string - 格式异常字符串 - - - missing closing quote - 缺少闭合引号 - - - %1: (row, col) %2,%3 - %1:(行,列)%2,%3 - AES 256-bit AES 256 位 @@ -8667,12 +9151,88 @@ This option is deprecated, use --set-key-file instead. 快捷键 - Unsupported KDF type, cannot decrypt json file - 不支持的 KDF 类型,无法解密 JSON 文件 + Unknown passkeys error + 未知通行密钥错误 - Unknown passkeys error - + Invalid KDF iterations, cannot decrypt json file + 无效的 KDF 迭代数,无法解密 JSON 文件 + + + Unsupported format, ensure your Bitwarden export is password-protected + 不支持的格式,请确认您的 Bitwarden 导出文件受密码保护 + + + Only PBKDF and Argon2 are supported, cannot decrypt json file + 仅有 PBKDF 和 Argon2 受支持,无法解密 JSON 文件 + + + Reset Shortcuts + 重置快捷键 + + + Double click an action to change its shortcut + 双击一个动作以修改其快捷键 + + + Filter... + 过滤… + + + Shortcut Conflict + 快捷键冲突 + + + Shortcut %1 conflicts with '%2'. Overwrite shortcut? + 快捷键 %1 与 '%2' 冲突。是否覆盖快捷键? + + + Cannot generate valid passphrases because the wordlist is too short + 因为词表太短,无法生成有效的口令 + + + Encrypted files are not supported. + 加密文件不支持。 + + + Proton Pass Import + Proton Pass 导入 + + + Delete plugin data? + 是否删除插件数据? + + + Delete plugin data from Entry(s)? + 是否从条目中删除插件数据? + + + Passkey + 通行密钥 + + + Format to use when exporting. Available choices are 'xml', 'csv' or 'html'. Defaults to 'xml'. + 导出时使用的格式。可用的选项是“xml”、“csv”或“html”。默认值为“xml”。 + + + start minimized to the system tray + 启动时最小化到系统托盘 + + + malformed string, possible unescaped delimiter + 不合法的字符串,可能存在未转义的分隔符 + + + missing closing delimiter + 缺少闭合分隔符 + + + %1, row: %2, column: %3 + %1,行:%2,列:%3 + + + Tags + 标签 @@ -8709,6 +9269,37 @@ This option is deprecated, use --set-key-file instead. 内部 zlib 错误: + + RemoteHandler + + Command `%1` did not finish in time. Process was killed. + 命令 `%1` 未能及时完成。进程已被强制结束。 + + + Failed to upload merged database. Command `%1` did not finish in time. Process was killed. + 上传已合并的数据库失败。命令 `%1` 未能及时完成。进程已被强制结束。 + + + Invalid download parameters provided. + 提供的下载参数无效。 + + + Command `%1` failed to download database. + 命令 `%1` 下载数据库失败。 + + + Invalid database pointer or upload parameters provided. + 提供的数据库指针或上传参数无效。 + + + Command `%1` exited with status code: %2 + 命令 `%1` 以此状态码退出:%2 + + + Failed to upload merged database. Command `%1` exited with status code: %2 + 上传已合并的数据库失败。命令 `%1` 以此状态码退出:%2 + + ReportsWidgetBrowserStatistics @@ -8775,6 +9366,10 @@ This option is deprecated, use --set-key-file instead. Exclude from reports 从报告中排除 + + Expire Entry(s)… + 过期条目… + Only show entries that have a URL 仅显示含有 URL 的条目 @@ -8791,36 +9386,33 @@ This option is deprecated, use --set-key-file instead. (Expired) (已过期) + + Delete plugin data from Entry(s)… + 从条目中删除插件数据… + ReportsWidgetHealthcheck - Hover over reason to show additional details. Double-click entries to edit. - 将鼠标指针悬停在原因上以显示其他详细信息。双击条目以编辑。 + Show expired entries + 显示过期的条目 - Bad - Password quality - 极差 + (Expired) + (已过期) + + + Hover over reason to show additional details. Double-click entries to edit. + 将鼠标指针悬停在原因上以显示其他详细信息。双击条目以编辑。 Bad — password must be changed 极差 — 必须更改密码 - - Poor - Password quality - 差劲 - Poor — password should be changed 差劲 — 应该更改密码 - - Weak - Password quality - 较弱 - Weak — consider changing the password 较弱 — 可考虑更改密码 @@ -8869,18 +9461,14 @@ This option is deprecated, use --set-key-file instead. Exclude from reports 从报告中排除 - - Show expired entries - 显示过期的条目 + + Expire Entry(s)… + 过期条目… Show entries that have been excluded from reports 显示已从报告中排除的条目 - - (Expired) - (已过期) - ReportsWidgetHibp @@ -8976,6 +9564,10 @@ This option is deprecated, use --set-key-file instead. Exclude from reports 从报告中排除 + + Expire Entry(s)… + 过期条目… + ReportsWidgetPasskeys @@ -9037,11 +9629,11 @@ This option is deprecated, use --set-key-file instead. Please wait, list of entries with passkeys is being updated… - + 请稍等,正在更新包含通行密钥的条目列表… No entries with passkeys. - + 无包含通行密钥的条目。 @@ -9217,6 +9809,14 @@ This option is deprecated, use --set-key-file instead. No agent running, cannot list identities. 代理未在运行,无法列出身份。 + + Failed to remove all SSH identities from agent. + 从代理中删除所有 SSH 身份失败。 + + + All SSH identities removed from agent. + 已从代理中删除所有 SSH 身份。 + SearchHelpWidget @@ -9502,29 +10102,6 @@ This option is deprecated, use --set-key-file instead. 已导出到 %1 - - ShortcutSettingsWidget - - Double click an action to change its shortcut - 双击一个动作以修改其快捷键 - - - Shortcut Conflict - 快捷键冲突 - - - Filter... - 过滤… - - - Shortcut %1 conflicts with '%2'. Overwrite shortcut? - 快捷键 %1 与 '%2' 冲突。是否覆盖快捷键? - - - Reset Shortcuts - 重置快捷键 - - TagModel @@ -9813,14 +10390,18 @@ Example: JBSWY3DPEHPK3PXP No hardware keys detected 未检测到硬件密钥 - - <p>If you own a <a href="https://www.yubico.com/">YubiKey</a> or <a href="https://onlykey.io">OnlyKey</a>, you can use it for additional security.</p><p>The key requires one of its slots to be programmed as <a href="https://docs.yubico.com/yesdk/users-manual/application-otp/challenge-response.html">HMAC-SHA1 Challenge-Response</a>.</p> - <p>如果您拥有 <a href="https://www.yubico.com/">YubiKey</a> 或 <a href="https://onlykey.io">OnlyKey</a>,则可以使用它来提高安全性。</p><p>硬件密钥要求将其中一个插槽编程为 HMAC-SHA1 质询响应<a href="https://docs.yubico.com/yesdk/users-manual/application-otp/challenge-response.html">。</p> - Refresh hardware keys 刷新硬件密钥 + + <p>If you own a <a href="https://www.yubico.com/">YubiKey</a> or <a href="https://onlykey.io">OnlyKey</a>, you can use it for additional security.</p><p>The key requires one of its slots to be programmed with <a href="https://keepassxc.org/docs/#faq-yubikey-howto">Challenge-Response</a>.</p> + <p>如果您拥有 <a href="https://www.yubico.com/">YubiKey</a> 或 <a href="https://onlykey.io">OnlyKey</a>,则可以使用它来提高安全性。</p><p>硬件密钥要求将其中一个插槽以<a href="https://keepassxc.org/docs/#faq-yubikey-howto">质询响应</a>编程。</p> + + + Hardware keys found, but no slots are configured + 硬件密钥已找到,但未配置任何插槽 + YubiKeyInterfacePCSC diff --git a/share/translations/keepassxc_zh_TW.ts b/share/translations/keepassxc_zh_TW.ts index 9350e7f90..228bfec93 100644 --- a/share/translations/keepassxc_zh_TW.ts +++ b/share/translations/keepassxc_zh_TW.ts @@ -217,18 +217,50 @@ You must restart the application to set the new language. Would you like to restart now? 必須重啟應用程式以使用新語言。您是否要現在重新啟動? - - Reset Settings? - 重置設定? - - - Are you sure you want to reset all general and security settings to default? - 您確定要重置所有通用和安全設定回預設值? - Select backup storage directory 選擇備份存放目錄 + + Confirm Reset + 確認重置 + + + Are you sure you want to reset all settings to default? + 您確定要重置所有設定回預設值? + + + Import KeePassXC Settings + 匯入 KeePassXC 設定 + + + Failed to import settings from %1, not a valid settings file. + 從 %1 匯入設定失敗,並非有效的設定檔案。 + + + Export KeePassXC Settings + 匯出 KeePassXC 設定 + + + Small + + + + Normal + 正常 + + + Medium + + + + Large + + + + Custom + 自定義 + ApplicationSettingsWidgetGeneral @@ -280,25 +312,6 @@ Include beta releases when checking for updates 檢查更新時包括 beta 版本 - - On database unlock, show entries that - 解鎖資料庫時,顯示符合條件的項目 - - - have expired - On database unlock, show entries that... - 已過期 - - - days - On database unlock, show entries that will expire within %1 days - - - - will expire within - On database unlock, show entries that... - 將過期於 - File Management 檔案管理 @@ -323,22 +336,10 @@ Backup database file before saving 儲存資料庫檔案前先備份 - - Backup destination - 備份目的地 - - - Specifies the database backup file location. Occurrences of "{DB_FILENAME}" are replaced with the filename of the saved database without extension. {TIME:<format>} is replaced with the backup time, see https://doc.qt.io/qt-5/qdatetime.html#toString. <format> defaults to format string "dd_MM_yyyy_hh-mm-ss". - 指定資料庫備份檔案位置。其中 "{DB_FILENAME}" 會被替換為保存資料庫的檔案名稱,不包含副檔名。{TIME:<format>} 會被替換為備份時間,詳見 https://doc.qt.io/qt-5/qdatetime.html#toString 。<format> 預設為格式字符串 "dd_MM_yyyy_hh-mm-ss"。 - {DB_FILENAME}.old.kdbx {DB_FILENAME}.old.kdbx - - Choose... - 選擇... - Use alternative saving method (may solve problems with Dropbox, Google Drive, GVFS, etc.) 使用替代儲存方案(或許能解決諸如 Dropbox、Google Drive、GVFS 的相關問題) @@ -505,6 +506,71 @@ Remember last typed entry for: 記住上次輸入的項目: + + On database unlock, show entries that will expire within + 解鎖資料庫時,顯示即將過期的項目 + + + On database unlock, show entries that will expire within + 解鎖資料庫時,顯示即將過期的項目 + + + days + number of days warning for password expiration + + + + Destination format: + 目標格式: + + + <html><head/><body><p><span style=" font-weight:600;">{DB_FILENAME}</span> is replaced with the filename of the saved database without extension</p><p><span style=" font-weight:600;">{TIME:&lt;format&gt;}</span> is replaced with the specified time format (default: dd_MM_yyyy_hh-mm-ss)</p><p>See the User Guide for more details</p></body></html> + <html><head/><body><p><span style=" font-weight:600;">{DB_FILENAME}</span> 將被替換爲儲存資料庫的檔案名稱,不含副檔名</p><p><span style=" font-weight:600;">{TIME:&lt;format&gt;}</span> 將被替換爲指定的時間格式 (預設:dd_MM_yyyy_hh-mm-ss)</p><p>查看使用者指南了解詳情</p></body></html> + + + Choose folder... + 選擇資料夾... + + + Show confirmation before moving entries to recycle bin + 移動項目至回收桶前提示確認 + + + Copy data on double clicking field in entry view + 在項目視區中,雙擊欄位複製資料 + + + Show toolbar + 顯示工具列 + + + Show the menu bar by pressing the Alt key + 按下 Alt 鍵顯示選單列 + + + Show menubar + 顯示選單列 + + + Import settings… + 匯入設定… + + + Export settings… + 匯出設定… + + + Open browser on double clicking URL field in entry view + 在項目視區中,雙擊 URL 打開瀏覽器 + + + Font size: + 字型: + + + Font size selection + 字型大小選擇 + ApplicationSettingsWidgetSecurity @@ -570,18 +636,6 @@ Hide passwords in the entry preview panel 隱藏項目預覽面板內的密碼 - - Hide entry notes by default - 預設隱藏項目備註 - - - Move entries to recycle bin without confirmation - 無需確認就移動項目到回收桶 - - - Enable double click to copy the username/password entry columns - 啟用滑鼠雙擊複製「使用者名稱/密碼」項目欄位 - Privacy 隱私 @@ -594,6 +648,18 @@ Hide TOTP in the entry preview panel 隱藏項目預覽面板上的 TOTP + + Lock databases when switching user + 切換使用者時鎖定資料庫 + + + Lock Options + 鎖定選項 + + + Hide notes in the entry preview panel + 隱藏項目預覽面板內的備註 + AutoType @@ -641,20 +707,6 @@ Entry does not have attribute for PICKCHARS: %1 項目不包含用於 PICKCHARS 的屬性:%1 - - Invalid conversion type: %1 - 無效的轉換類型: %1 - - - Invalid conversion syntax: %1 - 無效的轉換語法: %1 - - - Invalid regular expression syntax %1 -%2 - 無效的正規表示式語法 %1 -%2 - Invalid placeholder: %1 無效的佔位符: %1 @@ -886,24 +938,25 @@ Please select the correct database for saving credentials. Add to existing entry - + 加入至現有項目 Existing passkey found. Do you want to register a new passkey for: - + 發現既有的通行密鑰。 +是否要註冊新的通行密鑰: Select the existing passkey and press Update to replace it. - + 選擇既有的通行密鑰並按下「更新」來替換它。 Authenticate passkey credentials for: - + 驗證通行密鑰憑證: Do you want to register a passkey for: - + 是否要註冊通行密鑰: @@ -988,16 +1041,17 @@ Do you want to delete the entry? Register a new passkey to this entry: - + 註冊新的通行密鑰至此項目: KeePassXC - Update passkey - + KeePassXC - 更新通行密鑰 Entry already has a passkey. Do you want to overwrite the passkey in %1 - %2? - + 項目已經擁有一組通行密鑰。 +是否要覆寫位於 %1 - %2 的通行密鑰? Register @@ -1022,10 +1076,6 @@ Do you want to overwrite the passkey in %1 - %2? General 一般 - - Browsers installed as snaps are currently not supported. - 目前並不支援以 Snap 套件安裝的瀏覽器。 - Enable integration for these browsers: 為以下瀏覽器啟用整合功能: @@ -1197,18 +1247,6 @@ Do you want to overwrite the passkey in %1 - %2? Custom extension ID 自定義擴充 ID - - Due to Snap sandboxing, you must run a script to enable browser integration.<br />You can obtain this script from %1 - 由於 Snap 的沙盒機制,您必須執行一個腳本來啟用瀏覽器整合。<br />您可以從 %1 取得這個腳本 - - - KeePassXC-Browser is needed for the browser integration to work. <br />Download it for %1 and %2 and %3. %4 - 需要 KeePassXC 瀏覽器擴充才能使用整合功能。<br />可供 %1 和 %2 和 %3 下載。%4 - - - Please see special instructions for browser extension use below - 請參閱以下的具體指示,學習如何使用瀏覽器擴展 - Executable Files 可執行檔案 @@ -1251,11 +1289,19 @@ Do you want to overwrite the passkey in %1 - %2? Allows using insecure http://localhost with passkeys for testing purposes. - + 允許通行密鑰使用不安全的 http://localhost 作為測試用途。 Allow using localhost with passkeys - + 允許通行密鑰使用 localhost + + + KeePassXC-Browser is needed for the browser integration to work. <br />Download it for %1 and %2 and %3. + 需要 KeePassXC 瀏覽器擴充才能使用整合功能。<br />可供 %1 和 %2 和 %3 下載。 + + + Browsers installed using Snap or Flatpak are not supported with exception to Firefox installed using Snap. + 不支援用 Snap 或 Flatpak 安裝的瀏覽器;Snap 安裝的 Firefox 為例外。 @@ -1399,6 +1445,20 @@ Do you want to overwrite the passkey in %1 - %2? Imported from CSV file: %1 匯入自 CSV 檔案:%1 + + No Title Selected + 未選擇標題 + + + No title column was selected, entries will be hard to tell apart. +Are you sure you want to import? + 未選擇標題欄,項目將難以區分。 +您確定要匯入嗎? + + + Tags + 標籤 + CsvParserModel @@ -1462,6 +1522,14 @@ Backup database located at %2 Recycle Bin 回收桶 + + Database file read error. + 資料庫檔案讀取錯誤。 + + + No file path was provided. + 未提供檔案路徑。 + DatabaseOpenDialog @@ -1610,14 +1678,6 @@ To prevent this error from appearing, you must go to "Database Settings / S <p>In addition to a password, you can use a secret file to enhance the security of your database. This file can be generated in your database's security settings.</p><p>This is <strong>not</strong> your *.kdbx database file!</p> <p>除了密碼,您還可以使用一份袐密檔案來加強資料庫的安全性。此檔案可以透過資料庫的安全設定中生成。</p><p>這<strong>不是</strong>您的 *.kdbx 資料庫檔案!</p> - - Click to add a key file. - 點擊以加入金鑰檔案。 - - - <a href="#" style="text-decoration: underline">I have a key file</a> - <a href="#" style="text-decoration: underline">我有一份金鑰檔案</a> - Use hardware key [Serial: %1] 使用硬體金鑰 [序號: %1] @@ -1654,6 +1714,18 @@ Are you sure you want to continue with this file?. Refresh Hardware Keys 刷新硬體金鑰 + + Click to add a key file. + 點擊以加入金鑰檔案。 + + + <a href="#" style="text-decoration: underline">I have a key file</a> + <a href="#" style="text-decoration: underline">我有一份金鑰檔案</a> + + + Hardware keys found, but no slots are configured. + 硬體金鑰已找到,但未配置任何槽位。 + DatabaseSettingWidgetMetaData @@ -1688,6 +1760,22 @@ Are you sure you want to continue with this file?. Maintenance 維護 + + KeeShare + KeeShare + + + Secret Service Integration + 保密服務整合 + + + Remote Sync + 遠端同步 + + + Database Settings: %1 + 資料庫設定:%1 + DatabaseSettingsWidgetBrowser @@ -1858,14 +1946,14 @@ Are you sure you want to continue without a password? Weak password 弱密碼 - - You must enter a stronger password to protect your database. - 您必須輸入更強的密碼來保護資料庫。 - This is a weak password! For better protection of your secrets, you should choose a stronger password. 這是一個弱密碼!為了更好地保護您的祕密,您應該選擇更強的密碼。 + + The provided password does not meet the minimum quality requirement. + 提供的密碼未達到最低強度要求。 + DatabaseSettingsWidgetEncryption @@ -2167,6 +2255,50 @@ removed from the database. Autosave delay since last change checkbox 自動儲存延遲勾選框 + + Public Database Metadata + 公開資料庫詮釋資料 + + + Warning: the following settings are not encrypted. + 警告:以下設定並未被加密。 + + + Display name: + 顯示名稱: + + + Publically visible display name used on the unlock dialog + 公開可見的顯示名稱,於解鎖對話框 + + + Database public display name + 資料庫的公開顯示名稱 + + + Display color: + 顯示顏色: + + + Publically visible color used on the unlock dialog + 公開可見的顏色,於解鎖對話框 + + + Database public display color chooser + 資料庫的公開顯示顏色選擇器 + + + Clear + 清除 + + + Display icon: + 顯示圖示: + + + Select Database Icon + 選擇資料庫圖示 + DatabaseSettingsWidgetKeeShare @@ -2262,6 +2394,141 @@ removed from the database. 資料庫描述欄位 + + DatabaseSettingsWidgetRemote + + Sync Commands + 同步指令 + + + Remove + 移除 + + + Command Settings + 指令設定 + + + Name + 名稱 + + + Save + 儲存 + + + Download + 下載 + + + Command: + 指令: + + + Download command field + 下載指令欄 + + + e.g.: "sftp user@hostname" or "scp user@hostname:DatabaseOnRemote.kdbx {TEMP_DATABASE}" + 範例:"sftp user@hostname" 或者 "scp user@hostname:DatabaseOnRemote.kdbx {TEMP_DATABASE}" + + + Input: + 輸入: + + + Download input field + 下載輸入欄 + + + Upload + 上傳 + + + Upload command field + 上傳指令欄 + + + e.g.: "sftp user@hostname" or "scp {TEMP_DATABASE} user@hostname:DatabaseOnRemote.kdbx" + 範例:"sftp user@hostname" 或者 "scp {TEMP_DATABASE} user@hostname:DatabaseOnRemote.kdbx" + + + Upload input field + 上傳輸入欄 + + + Name cannot be empty. + 名稱不可爲空。 + + + Test + 測試 + + + Download command cannot be empty. + 下載命令不可爲空。 + + + Download failed with error: %1 + 下載失敗,錯誤:%1 + + + Download finished, but file %1 could not be found. + 下載完成,但無法找到檔案 %1。 + + + Download successful. + 下載成功。 + + + Save Remote Settings + 儲存遠端設定 + + + You have unsaved changes. Do you want to save them? + 您有未保存的更改。是否要保存它們? + + + e.g.: +get DatabaseOnRemote.kdbx {TEMP_DATABASE} +exit +--- +{TEMP_DATABASE} is used as placeholder to store the database in a temporary location +The command has to exit. In case of `sftp` as last command `exit` has to be sent + + 範例: +get DatabaseOnRemote.kdbx {TEMP_DATABASE} +exit +--- +{TEMP_DATABASE} 作為占位符,表示保存資料庫的臨時位置 +命令必須可以退出。如果最後一個指令爲 `sftp` 則必須發送 `exit` 指令 + + + + e.g.: +put {TEMP_DATABASE} DatabaseOnRemote.kdbx +exit +--- +{TEMP_DATABASE} is used as placeholder to store the database in a temporary location +The command has to exit. In case of `sftp` as last command `exit` has to be sent + + 範例: +put {TEMP_DATABASE} DatabaseOnRemote.kdbx +exit +--- +{TEMP_DATABASE} 作為占位符,表示保存資料庫的臨時位置 +命令必須可以退出。如果最後一個指令爲 `sftp` 則必須發送 `exit` 指令 + + + + Timeout: + 超時: + + + seconds + + + DatabaseTabWidget @@ -2335,6 +2602,11 @@ This is definitely a bug, please report it to the developers. Database tab name modifier %1 [已鎖定] + + %1 [Temporary] + Database tab name modifier + %1 [臨時] + DatabaseWidget @@ -2458,26 +2730,6 @@ Save changes? File has changed 檔案已變更 - - The database file has changed. Do you want to load the changes? - 資料庫檔案已被修改。是否要載入變更? - - - Merge Request - 合併要求 - - - The database file has changed and you have unsaved changes. -Do you want to merge your changes? - 資料庫檔案已被修改,且您有尚未儲存的變更。 -是否合併您的變更? - - - Could not open the new database file while attempting to autoreload. -Error: %1 - 嘗試自動重新載入,無法開啓新的資料庫檔案。 -錯誤:%1 - Disable safe saves? 停用安全存檔? @@ -2529,6 +2781,86 @@ Disable safe saves and try again? Database tab name modifier %1 [新資料庫] + + Remote Sync did not contain any download or upload commands. + 遠端同步未包含任何下載或上傳指令。 + + + Remote sync '%1' completed successfully! + 遠端同步「%1」成功完成! + + + Remote sync '%1' failed: %2 + 遠端同步「%1」失敗:%2 + + + Error while saving database %1: %2 + 儲存資料庫 %1 時發生錯誤:%2 + + + Downloading... + 正在下載... + + + Uploading... + 正在上傳... + + + Syncing... + 正在同步... + + + Remove passkey from entry + 從項目移除通行密鑰 + + + Do you want to remove the passkey from this entry? + 是否要從此項目移除通行密鑰? + + + The database file "%1" was modified externally + 資料庫檔案「%1」被外部更動 + + + Do you want to load the changes? + 是否要載入變更? + + + Reload database + 重載資料庫 + + + Reloading database… + 正在重載資料庫… + + + Reload canceled + 重載取消 + + + Reload successful + 重載成功 + + + Reload pending user action… + 重載等待使用者行動… + + + The database file "%1" was modified externally.<br>How would you like to proceed?<br><br>Merge all changes<br>Ignore the changes on disk until save<br>Discard unsaved changes + 資料庫檔案「%1」曾被外部修改過 。<br>您希望如何進行?<br><br>合併所有變更<br>儲存前先忽略磁碟上的變更<br>丟棄未儲存的變更 + + + The database file "%1" was modified externally.<br>How would you like to proceed?<br><br>Merge all changes then save<br>Overwrite the changes on disk<br>Discard unsaved changes + 資料庫檔案「%1」曾被外部修改過 。<br>您希望如何進行?<br><br>合併所有變更並儲存<br>覆寫磁碟上的變更<br>丟棄未儲存的變更 + + + Database file overwritten. + 資料庫檔案被覆寫。 + + + Database file on disk cannot be unlocked with current credentials.<br>Enter new credentials and/or present hardware key to continue. + 磁碟上的資料庫檔案無法被現有憑證解鎖。<br>輸入新的憑證並/或出示硬體金鑰以繼續。 + EditEntryWidget @@ -2580,10 +2912,6 @@ Disable safe saves and try again? n/a - - (encrypted) - (已加密) - Select private key 選擇私密金鑰 @@ -2686,6 +3014,10 @@ Would you like to correct it? %n year(s) %n 年 + + Failed to decrypt SSH key, ensure password is correct. + 解密 SSH 金鑰失敗,確認密碼是否正確。 + EditEntryWidgetAdvanced @@ -2747,7 +3079,7 @@ Would you like to correct it? If checked, the entry will not appear in reports like Health Check and HIBP even if it doesn't match the quality requirements. - 勾選後,項目將不會出現在「健康檢查」或 HIBP 等報告,即使它不符合品質要求。 + 勾選後,項目將不會出現在「健康檢查」或 HIBP 等報告,即使它不符合強度要求。 Exclude from database reports @@ -2857,18 +3189,10 @@ Would you like to correct it? Skip Auto-Submit for this entry 為此項目跳過自動送出 - - Only send this setting to the browser for HTTP Auth dialogs. If enabled, normal login forms will not show this entry for selection. - 只有出現 HTTP 基本認證對話框才會傳送此設定至瀏覽器。啟用之後,將不會在一般的登入表格顯示此項目的選項。 - Use this entry only with HTTP Basic Auth 對此項目只使用 HTTP 基本認證 - - Do not send this setting to the browser for HTTP Auth dialogs. If enabled, HTTP Auth dialogs will not show this entry for selection. - 對 HTTP 基本認證對話框,不要傳送此設定至瀏覽器。啟用之後,HTTP 基本認證對話框將不會在選項中顯示此項目。 - Do not use this entry with HTTP Basic Auth HTTP 基本認證不要使用此項目 @@ -2893,6 +3217,14 @@ Would you like to correct it? Additional URLs 其他 URL + + Only send this entry to the browser for HTTP Auth dialogs. If enabled, normal login forms will not show this entry for selection. + 僅將此項目傳送到瀏覽器的 HTTP 認證對話框。啟用後,普通登入表格將不再顯示此項目供選擇。 + + + Do not send this entry to the browser for HTTP Auth dialogs. If enabled, HTTP Auth dialogs will not show this entry for selection. + 不要將此項目傳送到瀏覽器的 HTTP 認證對話框。啟用後,HTTP 認證對話框將不再顯示此項目供選擇。 + EditEntryWidgetHistory @@ -3115,6 +3447,10 @@ Would you like to correct it? seconds + + Clear agent + 清除代理 + EditGroupWidget @@ -3557,6 +3893,24 @@ This may cause the affected plugins to malfunction. %1 - Clone %1 - 複製 + + Passkey + 通行密鑰 + + + Invalid conversion type: %1 + 無效的轉換類型: %1 + + + Invalid conversion syntax: %1 + 無效的轉換語法: %1 + + + Invalid regular expression syntax %1 +%2 + 無效的正規表示式語法 %1 +%2 + EntryAttachments @@ -3565,6 +3919,21 @@ This may cause the affected plugins to malfunction. 無法開啟檔案「%1」 + + EntryAttachmentsDialog + + Form + 表單 + + + File name + 檔案名稱 + + + File contents... + 檔案內容... + + EntryAttachmentsModel @@ -3602,14 +3971,6 @@ This may cause the affected plugins to malfunction. Remove 移除 - - Rename selected attachment - 重新命名所選附件 - - - Rename - 重新命名 - Open selected attachment 開啟所選附件 @@ -3723,6 +4084,18 @@ Would you like to overwrite the existing attachment? 附件「%1」已存在。 是否要覆改既存的附件? + + New + + + + Preview + 預覽 + + + Failed to preview an attachment: Attachment not found + 預覽附件失敗:找不到附件 + EntryAttributesModel @@ -3921,6 +4294,10 @@ Would you like to overwrite the existing attachment? Background Color 背景顏色 + + Group Path + 群組路徑 + EntryPreviewWidget @@ -4316,6 +4693,14 @@ You can enable the DuckDuckGo website icon service in the security section of th Url Url + + Could not load key file. + 無法載入金鑰檔。 + + + Could not open remote database. Password or key file may be incorrect. + 無法開啟遠端資料庫。密碼或金鑰檔可能不正確。 + ImportWizardPageSelect @@ -4419,6 +4804,50 @@ You can enable the DuckDuckGo website icon service in the security section of th KeePass1 Database KeePass1 資料庫 + + Proton Pass (.json) + Proton Pass (.json) + + + Proton Pass JSON Export + Proton Pass JSON 匯出 + + + Temporary Database + 臨時資料庫 + + + Command: + 指令: + + + e.g.: "sftp user@hostname" or "scp user@hostname:DatabaseOnRemote.kdbx {TEMP_DATABASE}" + 範例:"sftp user@hostname" 或者 "scp user@hostname:DatabaseOnRemote.kdbx {TEMP_DATABASE}" + + + Input: + 輸入: + + + e.g.: +get DatabaseOnRemote.kdbx {TEMP_DATABASE} +exit +--- +{TEMP_DATABASE} is used as placeholder to store the database in a temporary location +The command has to exit. In case of `sftp` as last commend `exit` has to be sent + + 範例: +get DatabaseOnRemote.kdbx {TEMP_DATABASE} +exit +--- +{TEMP_DATABASE} 作為占位符,表示保存資料庫的臨時位置 +命令必須可以退出。如果最後一個指令爲 `sftp` 則必須發送 `exit` 指令 + + + + Remote Database (.kdbx) + 遠端資料庫 (.kdbx) + KMessageWidget @@ -5559,12 +5988,6 @@ This version is not meant for production use. Expect some bugs and minor issues, this version is meant for testing purposes. 注意:您正在使用 KeePassXC 的預先發行版本。 此版本發行為測試用途,可能會出現一些程式錯誤和小問題。 - - - WARNING: Your Qt version may cause KeePassXC to crash with an On-Screen Keyboard. -We recommend you use the AppImage available on our downloads page. - 警告:您的 Qt 版本可能會導致 KeePassXC 與螢幕鍵盤崩潰。 -建議您使用我們下載頁面上提供的 AppImage。 No Tags @@ -5638,6 +6061,10 @@ We recommend you use the AppImage available on our downloads page. Import Passkey 匯入通行密鑰 + + Remote S&ync… + 遠端同步(&Y)… + Quit Application 退出應用程式 @@ -5742,6 +6169,10 @@ We recommend you use the AppImage available on our downloads page. Show Password Generator 顯示密碼產生器 + + Remove Passkey From Entry + 從項目移除通行密鑰 + Perform Auto-Type: {USERNAME} 執行自動輸入:{USERNAME} @@ -5886,6 +6317,34 @@ We recommend you use the AppImage available on our downloads page. Toggle Allow Screen Capture 切換允許螢幕截圖 + + Show Group Panel + 顯示群組面板 + + + Toggle Show Group Panel + 切換顯示群組面板 + + + Setup Remote Sync… + 設定遠端同步… + + + Password Generator + 密碼產生器 + + + E&xpire Entry… + 過期項目(&X)… + + + Clear SSH Agent + 清楚 SSH 代理 + + + Clear all identities in ssh-agent + 清楚 ssh-agent 內所有身份 + ManageDatabase @@ -6036,6 +6495,25 @@ We recommend you use the AppImage available on our downloads page. 請為您的新資料庫填寫一個顯示名稱,及一個選擇性的說明: + + NewEntryAttachmentsDialog + + Attachment name cannot be empty + 附件名稱不能為空 + + + Attachment with the same name already exists + 已存在相同名稱的附件 + + + Save attachment + 儲存附件 + + + New entry attachment + 新項目附件 + + NixUtils @@ -6223,6 +6701,10 @@ We recommend you use the AppImage available on our downloads page. Unexpected EOF when writing private key 寫入私密金鑰時出現意外的檔案結尾 + + (encrypted) + (已加密) + OpenSSHKeyGenDialog @@ -6271,7 +6753,7 @@ We recommend you use the AppImage available on our downloads page. Export the following passkey entries. - + 匯出以下通行密鑰項目。 @@ -6345,15 +6827,15 @@ Do you want to overwrite it? Import the following passkey: - + 匯入以下通行密鑰: Import the following passkey to this entry: - + 將以下通行密鑰匯入至此項目: Default passkeys group (Imported Passkeys) - + 預設的通行密鑰群組(匯入的通行密鑰) @@ -6376,25 +6858,27 @@ Do you want to overwrite it? Open passkey file - + 開啟通行密鑰檔案 Cannot import passkey - + 無法匯入通行密鑰 Cannot import passkey file "%1". Data is missing. - + 無法匯入通行密鑰檔案「%1」。資料遺失。 Cannot import passkey file "%1". The following data is missing: %2 - + 無法匯入通行密鑰檔案「%1」。 +以下資料有遺失: +%2 Cannot import passkey file "%1". Private key is missing or malformed. - + 無法匯入通行密鑰檔案「%1」。私鑰遺失或格式有誤。 @@ -6575,10 +7059,6 @@ The following data is missing: Also choose from: 也從此選擇: - - Excluded characters: "0", "1", "l", "I", "O", "|", "﹒" - 排除以下字元:"0", "1", "l", "I", "O", "|", "﹒" - Exclude look-alike characters 去除相似的字元 @@ -6603,10 +7083,6 @@ The following data is missing: Word Count: 詞彙數: - - Character Count: - 字元數: - Word Case: 字母大小寫: @@ -6619,10 +7095,6 @@ The following data is missing: Add custom wordlist 加入自定義詞彙表 - - character - 字元 - Close 關閉 @@ -6661,7 +7133,7 @@ The following data is missing: Password Quality: %1 - 密碼品質:%1 + 密碼強度:%1 Poor @@ -6729,6 +7201,22 @@ Do you want to overwrite it? Special Characters 特殊字元 + + passwordLength + 密碼長度 + + + Characters: %1 + 字元:%1 + + + MIXED case + 大小寫混合 + + + Excluded characters: "0", "1", "l", "I", "O", "|", "﹒", "B", "8", "G", "6" + 排除字元:"0", "1", "l", "I", "O", "|", "﹒", "B", "8", "G", "6" + PasswordWidget @@ -6754,7 +7242,7 @@ Do you want to overwrite it? Quality: %1 - 密碼品質:%1 + 密碼強度:%1 Poor @@ -6796,6 +7284,21 @@ Do you want to overwrite it? 字元間按 &Tab + + PreviewEntryAttachmentsDialog + + Preview entry attachment + 預覽項目附件 + + + No preview available + 無適用的預覽 + + + Image format not supported + 圖像格式不受支援 + + QMessageBox @@ -7463,7 +7966,7 @@ Do you want to overwrite it? Wordlist for the diceware generator. [Default: EFF English] - Diceware 產生器使用的字詞表。 + Diceware 產生器使用的詞彙表。 [預設:EFF English] @@ -7474,10 +7977,6 @@ Do you want to overwrite it? Invalid word count %1 無效的字數統計 %1 - - The word list is too small (< 1000 items) - 字詞清單過小(< 1000 個項目) - Title for the entry. 項目標題。 @@ -7622,10 +8121,6 @@ Do you want to overwrite it? Exit interactive mode. 離開互動模式。 - - Format to use when exporting. Available choices are 'xml' or 'csv'. Defaults to 'xml'. - 匯出所用的格式。可用選項為 'xml' 或 'csv'。預設為 'xml'。 - Exports the content of a database to standard output in the specified format. 以指定格式匯出資料庫內容至標準輸出。 @@ -8214,18 +8709,6 @@ Kernel: %3 %4 file empty 檔案為空 - - malformed string - 格式不正確的字串 - - - missing closing quote - 缺少右引號 - - - %1: (row, col) %2,%3 - %1: (列, 行) %2,%3 - AES 256-bit AES 256-bit @@ -8671,12 +9154,88 @@ This option is deprecated, use --set-key-file instead. 快捷鍵 - Unsupported KDF type, cannot decrypt json file - 不支援的 KDF 類型,無法解密 JSON 檔案 + Unknown passkeys error + 未知的通行密鑰錯誤 - Unknown passkeys error - + Invalid KDF iterations, cannot decrypt json file + 無效的 KDF 迭代數,無法解密 JSON 檔案 + + + Unsupported format, ensure your Bitwarden export is password-protected + 不支援的格式,確保您的 Bitwarden 匯出檔爲密碼保護 + + + Only PBKDF and Argon2 are supported, cannot decrypt json file + 只支援 PBKDF 與 Argon2,無法解密 JSON 檔案 + + + Reset Shortcuts + 重置快捷鍵 + + + Double click an action to change its shortcut + 雙擊一個動作以修改其快捷鍵 + + + Filter... + 過濾... + + + Shortcut Conflict + 快捷鍵衝突 + + + Shortcut %1 conflicts with '%2'. Overwrite shortcut? + 快捷鍵 %1 與 '%2' 衝突。是否覆蓋快捷鍵? + + + Cannot generate valid passphrases because the wordlist is too short + 因為詞彙表過短,無法生成有效的密碼短語 + + + Encrypted files are not supported. + 尚未支援加密檔案。 + + + Proton Pass Import + Proton Pass 匯入 + + + Delete plugin data? + 刪除插件資料? + + + Delete plugin data from Entry(s)? + 是否從項目刪除插件資料? + + + Passkey + 通行密鑰 + + + Format to use when exporting. Available choices are 'xml', 'csv' or 'html'. Defaults to 'xml'. + 匯出所用的格式。可用選項為 'xml', 'csv' 或 'html'。預設為 'xml'。 + + + start minimized to the system tray + 啟動後最小化至系統列 + + + malformed string, possible unescaped delimiter + 不合規的字串,可能有未跳脫的分隔符 + + + missing closing delimiter + 缺少閉合分隔符 + + + %1, row: %2, column: %3 + %1,列:%2,欄:%3 + + + Tags + 標籤 @@ -8713,6 +9272,37 @@ This option is deprecated, use --set-key-file instead. 內部 zlib 錯誤: + + RemoteHandler + + Command `%1` did not finish in time. Process was killed. + 指令 `%1` 未能及時完成。程序已被強制結束。 + + + Failed to upload merged database. Command `%1` did not finish in time. Process was killed. + 上傳已合併的資料庫失敗。指令 `%1` 未能及時完成。程序已被強制結束。 + + + Invalid download parameters provided. + 提供的下載參數無效。 + + + Command `%1` failed to download database. + 指令 `%1` 下載資料庫失敗。 + + + Invalid database pointer or upload parameters provided. + 提供的資料庫指針或上傳參數無效。 + + + Command `%1` exited with status code: %2 + 指令 `%1` 以此狀態碼退出:%2 + + + Failed to upload merged database. Command `%1` exited with status code: %2 + 上傳已合併的資料庫失敗。指令 `%1` 以此狀態碼退出:%2 + + ReportsWidgetBrowserStatistics @@ -8779,6 +9369,10 @@ This option is deprecated, use --set-key-file instead. Exclude from reports 從報告排除 + + Expire Entry(s)… + 過期項目… + Only show entries that have a URL 只顯示含有 URL 的項目 @@ -8795,36 +9389,33 @@ This option is deprecated, use --set-key-file instead. (Expired) (過期) + + Delete plugin data from Entry(s)… + 從項目刪除插件資料… + ReportsWidgetHealthcheck - Hover over reason to show additional details. Double-click entries to edit. - 將游標懸浮於原因以顯示額外詳情。雙擊項目可編輯。 + Show expired entries + 顯示過期項目 - Bad - Password quality - 糟糕 + (Expired) + (過期) + + + Hover over reason to show additional details. Double-click entries to edit. + 將游標懸浮於原因以顯示額外詳情。雙擊項目可編輯。 Bad — password must be changed 糟糕 — 密碼必須更改 - - Poor - Password quality - 極弱 - Poor — password should be changed 極弱 — 密碼應該更改 - - Weak - Password quality - 較弱 - Weak — consider changing the password 較弱 — 可考慮更改密碼 @@ -8873,18 +9464,14 @@ This option is deprecated, use --set-key-file instead. Exclude from reports 從報告排除 - - Show expired entries - 顯示過期項目 + + Expire Entry(s)… + 過期項目… Show entries that have been excluded from reports 顯示已從報告中排除的項目 - - (Expired) - (過期) - ReportsWidgetHibp @@ -8980,6 +9567,10 @@ This option is deprecated, use --set-key-file instead. Exclude from reports 從報告排除 + + Expire Entry(s)… + 過期項目… + ReportsWidgetPasskeys @@ -9041,11 +9632,11 @@ This option is deprecated, use --set-key-file instead. Please wait, list of entries with passkeys is being updated… - + 請稍候,正在更新擁有通行密鑰的項目清單… No entries with passkeys. - + 沒有附帶通行密鑰的項目。 @@ -9221,6 +9812,14 @@ This option is deprecated, use --set-key-file instead. No agent running, cannot list identities. 代理尚未執行,無法列舉身份。 + + Failed to remove all SSH identities from agent. + 從代理移除所有 SSH 身份失敗。 + + + All SSH identities removed from agent. + 所有 SSH 身份已從代理移除。 + SearchHelpWidget @@ -9506,29 +10105,6 @@ This option is deprecated, use --set-key-file instead. 匯出至 %1 - - ShortcutSettingsWidget - - Double click an action to change its shortcut - 雙擊一個動作以修改其快捷鍵 - - - Shortcut Conflict - 快捷鍵衝突 - - - Filter... - 過濾... - - - Shortcut %1 conflicts with '%2'. Overwrite shortcut? - 快捷鍵 %1 與 '%2' 衝突。是否覆蓋快捷鍵? - - - Reset Shortcuts - 重設快捷鍵 - - TagModel @@ -9817,14 +10393,18 @@ Example: JBSWY3DPEHPK3PXP No hardware keys detected 未偵測到硬體金鑰 - - <p>If you own a <a href="https://www.yubico.com/">YubiKey</a> or <a href="https://onlykey.io">OnlyKey</a>, you can use it for additional security.</p><p>The key requires one of its slots to be programmed as <a href="https://docs.yubico.com/yesdk/users-manual/application-otp/challenge-response.html">HMAC-SHA1 Challenge-Response</a>.</p> - <p>若您擁有 <a href="https://www.yubico.com/">YubiKey</a> 或 <a href="https://onlykey.io">OnlyKey</a>,可以用它獲得額外保護。</p><p>需要將鑰匙其中一個槽位設置為 <a href="https://docs.yubico.com/yesdk/users-manual/application-otp/challenge-response.html">HMAC-SHA1 挑戰應答</a>。</p> - Refresh hardware keys 刷新硬體金鑰 + + <p>If you own a <a href="https://www.yubico.com/">YubiKey</a> or <a href="https://onlykey.io">OnlyKey</a>, you can use it for additional security.</p><p>The key requires one of its slots to be programmed with <a href="https://keepassxc.org/docs/#faq-yubikey-howto">Challenge-Response</a>.</p> + <p>若您擁有 <a href="https://www.yubico.com/">YubiKey</a> 或 <a href="https://onlykey.io">OnlyKey</a>,可以用它獲得額外保護。</p><p>實體金鑰要求將其中一個槽位以 <a href="https://keepassxc.org/docs/#faq-yubikey-howto">挑戰應答</a>編程。</p> + + + Hardware keys found, but no slots are configured + 硬體金鑰已找到,但未配置任何槽位 + YubiKeyInterfacePCSC diff --git a/share/windows/wix-template.xml b/share/windows/wix-template.xml index add2af297..d90c6d51d 100644 --- a/share/windows/wix-template.xml +++ b/share/windows/wix-template.xml @@ -73,6 +73,7 @@ Name="KeePassXC - User Guide" Target="[#CM_FP_share.docs.KeePassXC_UserGuide.html]" WorkingDirectory="INSTALL_ROOT" /> + diff --git a/share/wordlists/eff_large.wordlist b/share/wordlists/eff_large.wordlist index f512e55d0..1a5ae7862 100644 --- a/share/wordlists/eff_large.wordlist +++ b/share/wordlists/eff_large.wordlist @@ -2006,7 +2006,6 @@ drizzly drone drool droop -drop-in dropforge dropkick droplet @@ -2525,7 +2524,6 @@ feed feel feisty feline -felt-tip feminine feminism feminist @@ -6637,7 +6635,6 @@ synthesis synthetic syrup system -t-shirt tabasco tabby tableful @@ -7745,7 +7742,6 @@ yiddish yield yin yippee -yo-yo yodel yoga yogurt diff --git a/snap/snapcraft.yaml b/snap/snapcraft.yaml index 29a8b34ed..598f07461 100644 --- a/snap/snapcraft.yaml +++ b/snap/snapcraft.yaml @@ -10,7 +10,7 @@ apps: command: usr/bin/keepassxc common-id: org.keepassxc.KeePassXC.desktop extensions: [kde-neon] - plugs: [home, unity7, network, network-bind, removable-media, raw-usb, password-manager-service] + plugs: [home, unity7, network, network-bind, removable-media, raw-usb, password-manager-service, browser-native-messaging] autostart: org.keepassxc.KeePassXC.desktop cli: command: usr/bin/keepassxc-cli @@ -19,7 +19,18 @@ apps: proxy: command: usr/bin/keepassxc-proxy extensions: [kde-neon] - plugs: [home] + +plugs: + browser-native-messaging: + interface: personal-files + write: + - $HOME/.mozilla/native-messaging-hosts/org.keepassxc.keepassxc_browser.json + - $HOME/.config/chromium/NativeMessagingHosts/org.keepassxc.keepassxc_browser.json + - $HOME/.config/google-chrome/NativeMessagingHosts/org.keepassxc.keepassxc_browser.json + - $HOME/.config/microsoft-edge/NativeMessagingHosts/org.keepassxc.keepassxc_browser.json + - $HOME/.config/vivaldi/NativeMessagingHosts/org.keepassxc.keepassxc_browser.json + - $HOME/.config/BraveSoftware/Brave-Browser/NativeMessagingHosts/org.keepassxc.keepassxc_browser.json + - $HOME/.local/share/torbrowser/tbb/x86_64/tor-browser_en-US/Browser/TorBrowser/Data/Browser/.mozilla/native-messaging-hosts/org.keepassxc.keepassxc_browser.json slots: session-dbus-interface: @@ -54,6 +65,7 @@ parts: - libxtst-dev - asciidoctor - libfreetype-dev + - libkeyutils-dev stage-packages: - dbus - libbotan-2-19 @@ -65,6 +77,7 @@ parts: - libxtst6 - libfreetype6 - xclip + - libkeyutils1 lint: ignore: - library: diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 40dae9371..9ddc46cf9 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -16,21 +16,19 @@ include_directories(${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR}) -find_library(ZXCVBN_LIBRARIES zxcvbn) -if(NOT ZXCVBN_LIBRARIES) - add_library(zxcvbn STATIC zxcvbn/zxcvbn.c) - # Disable error-level shadow issues - if(CC_HAS_Wshadow_compatible_local) - set_property(SOURCE zxcvbn/zxcvbn.c APPEND PROPERTY COMPILE_OPTIONS "-Wno-shadow-compatible-local") - endif() - if(CC_HAS_Wshadow_local) - set_property(SOURCE zxcvbn/zxcvbn.c APPEND PROPERTY COMPILE_OPTIONS "-Wno-shadow-local") - endif() - include_directories(${CMAKE_CURRENT_SOURCE_DIR}/zxcvbn) - set(ZXCVBN_LIBRARIES zxcvbn) -endif(NOT ZXCVBN_LIBRARIES) +add_feature_info(Auto-Type WITH_XC_AUTOTYPE "Automatic password typing") +add_feature_info(Networking WITH_XC_NETWORKING "Compile KeePassXC with network access code (e.g. for downloading website icons)") +add_feature_info(KeePassXC-Browser WITH_XC_BROWSER "Browser integration with KeePassXC-Browser") +add_feature_info(Passkeys WITH_XC_BROWSER_PASSKEYS "Passkeys support for browser integration") +add_feature_info(SSHAgent WITH_XC_SSHAGENT "SSH agent integration compatible with KeeAgent") +add_feature_info(KeeShare WITH_XC_KEESHARE "Sharing integration with KeeShare") +add_feature_info(YubiKey WITH_XC_YUBIKEY "YubiKey HMAC-SHA1 challenge-response") +add_feature_info(UpdateCheck WITH_XC_UPDATECHECK "Automatic update checking") +if(UNIX AND NOT APPLE) + add_feature_info(FdoSecrets WITH_XC_FDOSECRETS "Implement freedesktop.org Secret Storage Spec server side API.") +endif() -set(keepassx_SOURCES +set(core_SOURCES core/Alloc.cpp core/AutoTypeAssociations.cpp core/Base32.cpp @@ -61,7 +59,6 @@ set(keepassx_SOURCES core/Tools.cpp core/Totp.cpp core/Translator.cpp - core/UrlTools.cpp cli/Utils.cpp cli/TextStream.cpp crypto/Crypto.cpp @@ -74,6 +71,7 @@ set(keepassx_SOURCES format/BitwardenReader.cpp format/CsvExporter.cpp format/CsvParser.cpp + format/HtmlExporter.cpp format/KeePass1Reader.cpp format/KeePass2.cpp format/KeePass2RandomStream.cpp @@ -93,6 +91,20 @@ set(keepassx_SOURCES format/OpVaultReaderAttachments.cpp format/OpVaultReaderBandEntry.cpp format/OpVaultReaderSections.cpp + format/ProtonPassReader.cpp + keys/CompositeKey.cpp + keys/FileKey.cpp + keys/PasswordKey.cpp + keys/ChallengeResponseKey.cpp + streams/HashedBlockStream.cpp + streams/HashingStream.cpp + streams/HmacBlockStream.cpp + streams/LayeredStream.cpp + streams/qtiocompressor.cpp + streams/StoreDataStream.cpp + streams/SymmetricCipherStream.cpp) + +set(gui_SOURCES gui/styles/styles.qrc gui/styles/StateColorPalette.cpp gui/styles/base/phantomcolor.cpp @@ -100,6 +112,7 @@ set(keepassx_SOURCES gui/styles/dark/DarkStyle.cpp gui/styles/light/LightStyle.cpp gui/AboutDialog.cpp + gui/ActionCollection.cpp gui/Application.cpp gui/CategoryListWidget.cpp gui/Clipboard.cpp @@ -117,7 +130,7 @@ set(keepassx_SOURCES gui/FileDialog.cpp gui/Font.cpp gui/GuiTools.cpp - gui/HtmlExporter.cpp + gui/HtmlGuiExporter.cpp gui/IconModels.cpp gui/KMessageWidget.cpp gui/MainWindow.cpp @@ -128,13 +141,16 @@ set(keepassx_SOURCES gui/ApplicationSettingsWidget.cpp gui/Icons.cpp gui/SearchWidget.cpp + gui/SettingsWidget.cpp gui/SortFilterHideProxyModel.cpp gui/SquareSvgWidget.cpp + gui/ShortcutSettingsPage.cpp gui/TotpSetupDialog.cpp gui/TotpDialog.cpp gui/TotpExportSettingsDialog.cpp gui/DatabaseOpenDialog.cpp gui/URLEdit.cpp + gui/UrlTools.cpp gui/WelcomeWidget.cpp gui/csvImport/CsvImportWidget.cpp gui/csvImport/CsvParserModel.cpp @@ -143,6 +159,14 @@ set(keepassx_SOURCES gui/entry/EntryAttachmentsModel.cpp gui/entry/EntryAttachmentsWidget.cpp gui/entry/EntryAttributesModel.cpp + gui/entry/EditEntryAttachmentsDialog.cpp + gui/entry/PreviewEntryAttachmentsDialog.cpp + gui/entry/attachments/TextAttachmentsWidget.cpp + gui/entry/attachments/ImageAttachmentsWidget.cpp + gui/entry/attachments/ImageAttachmentsView.cpp + gui/entry/attachments/TextAttachmentsPreviewWidget.cpp + gui/entry/attachments/TextAttachmentsEditWidget.cpp + gui/entry/attachments/AttachmentWidget.cpp gui/entry/EntryHistoryModel.cpp gui/entry/EntryModel.cpp gui/entry/EntryView.cpp @@ -164,6 +188,10 @@ set(keepassx_SOURCES gui/dbsettings/DatabaseSettingsWidgetMetaDataSimple.cpp gui/dbsettings/DatabaseSettingsWidgetEncryption.cpp gui/dbsettings/DatabaseSettingsWidgetDatabaseKey.cpp + gui/remote/DatabaseSettingsWidgetRemote.cpp + gui/remote/RemoteHandler.cpp + gui/remote/RemoteProcess.cpp + gui/remote/RemoteSettings.cpp gui/reports/ReportsWidget.cpp gui/reports/ReportsDialog.cpp gui/reports/ReportsWidgetHealthcheck.cpp @@ -175,10 +203,10 @@ set(keepassx_SOURCES gui/osutils/OSUtilsBase.cpp gui/osutils/ScreenLockListener.cpp gui/osutils/ScreenLockListenerPrivate.cpp - gui/settings/SettingsWidget.cpp gui/widgets/ElidedLabel.cpp gui/widgets/KPToolBar.cpp gui/widgets/PopupHelpWidget.cpp + gui/widgets/ShortcutWidget.cpp gui/wizard/ImportWizard.cpp gui/wizard/ImportWizardPageReview.cpp gui/wizard/ImportWizardPageSelect.cpp @@ -187,83 +215,82 @@ set(keepassx_SOURCES gui/wizard/NewDatabaseWizardPageMetaData.cpp gui/wizard/NewDatabaseWizardPageEncryption.cpp gui/wizard/NewDatabaseWizardPageDatabaseKey.cpp - keys/CompositeKey.cpp - keys/FileKey.cpp - keys/PasswordKey.cpp - keys/ChallengeResponseKey.cpp - streams/HashedBlockStream.cpp - streams/HmacBlockStream.cpp - streams/LayeredStream.cpp - streams/qtiocompressor.cpp - streams/StoreDataStream.cpp - streams/SymmetricCipherStream.cpp) + quickunlock/QuickUnlockInterface.cpp + ../share/icons/icons.qrc + ../share/wizard/wizard.qrc) + if(APPLE) - set(keepassx_SOURCES - ${keepassx_SOURCES} - core/MacPasteboard.cpp + list(APPEND gui_SOURCES + gui/osutils/macutils/MacPasteboard.cpp gui/osutils/macutils/MacUtils.cpp gui/osutils/macutils/ScreenLockListenerMac.cpp gui/osutils/macutils/AppKitImpl.mm - gui/osutils/macutils/AppKit.h) + gui/osutils/macutils/AppKit.h + quickunlock/TouchID.mm) + + # TODO: Remove -Wno-error once deprecation warnings have been resolved. + set_source_files_properties(quickunlock/TouchID.mm PROPERTY COMPILE_FLAGS "-Wno-old-style-cast") endif() + if(UNIX AND NOT APPLE) - set(keepassx_SOURCES - ${keepassx_SOURCES} + list(APPEND gui_SOURCES gui/osutils/nixutils/ScreenLockListenerDBus.cpp gui/osutils/nixutils/NixUtils.cpp) + if("${CMAKE_SYSTEM}" MATCHES "Linux") + list(APPEND core_SOURCES + quickunlock/Polkit.cpp + quickunlock/PolkitDbusTypes.cpp) + endif() if(WITH_XC_X11) - list(APPEND keepassx_SOURCES + list(APPEND gui_SOURCES gui/osutils/nixutils/X11Funcs.cpp) endif() - qt5_add_dbus_adaptor(keepassx_SOURCES + qt5_add_dbus_adaptor(gui_SOURCES gui/org.keepassxc.KeePassXC.MainWindow.xml gui/MainWindow.h MainWindow) + + set_source_files_properties( + quickunlock/dbus/org.freedesktop.PolicyKit1.Authority.xml + PROPERTIES + INCLUDE "quickunlock/PolkitDbusTypes.h" + ) + qt5_add_dbus_interface(core_SOURCES + quickunlock/dbus/org.freedesktop.PolicyKit1.Authority.xml + polkit_dbus + ) + + find_library(KEYUTILS_LIBRARIES NAMES keyutils) + if(NOT KEYUTILS_LIBRARIES) + message(FATAL_ERROR "Could not find libkeyutils") + endif() endif() + if(WIN32) - set(keepassx_SOURCES - ${keepassx_SOURCES} + list(APPEND gui_SOURCES gui/osutils/winutils/ScreenLockListenerWin.cpp gui/osutils/winutils/WinUtils.cpp) if (MSVC) - list(APPEND keepassx_SOURCES winhello/WindowsHello.cpp) + list(APPEND gui_SOURCES quickunlock/WindowsHello.cpp) endif() endif() if(WITH_XC_YUBIKEY) - set(keepassx_SOURCES ${keepassx_SOURCES} gui/osutils/DeviceListener.cpp) + list(APPEND gui_SOURCES gui/osutils/DeviceListener.cpp) if(APPLE) - set(keepassx_SOURCES ${keepassx_SOURCES} gui/osutils/macutils/DeviceListenerMac.cpp) + list(APPEND gui_SOURCES gui/osutils/macutils/DeviceListenerMac.cpp) elseif(UNIX) - set(keepassx_SOURCES ${keepassx_SOURCES} gui/osutils/nixutils/DeviceListenerLibUsb.cpp) + list(APPEND gui_SOURCES gui/osutils/nixutils/DeviceListenerLibUsb.cpp) elseif(WIN32) - set(keepassx_SOURCES ${keepassx_SOURCES} gui/osutils/winutils/DeviceListenerWin.cpp) + list(APPEND gui_SOURCES gui/osutils/winutils/DeviceListenerWin.cpp) endif() endif() -set(keepassx_SOURCES ${keepassx_SOURCES} - ../share/icons/icons.qrc - ../share/wizard/wizard.qrc) - -set(keepassx_SOURCES_MAINEXE main.cpp) - -add_feature_info(Auto-Type WITH_XC_AUTOTYPE "Automatic password typing") -add_feature_info(Networking WITH_XC_NETWORKING "Compile KeePassXC with network access code (e.g. for downloading website icons)") -add_feature_info(KeePassXC-Browser WITH_XC_BROWSER "Browser integration with KeePassXC-Browser") -add_feature_info(Passkeys WITH_XC_BROWSER_PASSKEYS "Passkeys support for browser integration") -add_feature_info(SSHAgent WITH_XC_SSHAGENT "SSH agent integration compatible with KeeAgent") -add_feature_info(KeeShare WITH_XC_KEESHARE "Sharing integration with KeeShare") -add_feature_info(YubiKey WITH_XC_YUBIKEY "YubiKey HMAC-SHA1 challenge-response") -add_feature_info(UpdateCheck WITH_XC_UPDATECHECK "Automatic update checking") -if(UNIX AND NOT APPLE) - add_feature_info(FdoSecrets WITH_XC_FDOSECRETS "Implement freedesktop.org Secret Storage Spec server side API.") -endif() - add_subdirectory(browser) add_subdirectory(proxy) if(WITH_XC_BROWSER) - set(keepassxcbrowser_LIB keepassxcbrowser) - set(keepassx_SOURCES ${keepassx_SOURCES} + set(browser_LIB browser) + list(APPEND gui_SOURCES gui/dbsettings/DatabaseSettingsWidgetBrowser.cpp gui/entry/EntryURLModel.cpp gui/reports/ReportsWidgetBrowserStatistics.cpp @@ -271,7 +298,7 @@ if(WITH_XC_BROWSER) endif() if(WITH_XC_BROWSER_PASSKEYS) - set(keepassx_SOURCES ${keepassx_SOURCES} + list(APPEND gui_SOURCES gui/reports/ReportsWidgetPasskeys.cpp gui/reports/ReportsPagePasskeys.cpp gui/passkeys/PasskeyExporter.cpp @@ -303,123 +330,114 @@ endif() add_subdirectory(thirdparty) set(autotype_SOURCES - core/Tools.cpp autotype/AutoType.cpp autotype/AutoTypeAction.cpp autotype/AutoTypeMatchModel.cpp autotype/AutoTypeMatchView.cpp autotype/AutoTypeSelectDialog.cpp autotype/PickcharsDialog.cpp - autotype/ShortcutWidget.cpp autotype/WindowSelectComboBox.cpp) -if(WIN32) - set(keepassx_SOURCES_MAINEXE ${keepassx_SOURCES_MAINEXE} ${CMAKE_SOURCE_DIR}/share/windows/icon.rc) -endif() +add_library(autotype STATIC ${autotype_SOURCES}) +target_link_libraries(autotype Qt5::Core Qt5::Widgets) if(WITH_XC_YUBIKEY) - list(APPEND keepassx_SOURCES + list(APPEND core_SOURCES keys/drivers/YubiKey.h keys/drivers/YubiKey.cpp keys/drivers/YubiKeyInterface.cpp keys/drivers/YubiKeyInterfaceUSB.cpp keys/drivers/YubiKeyInterfacePCSC.cpp) else() - list(APPEND keepassx_SOURCES + list(APPEND core_SOURCES keys/drivers/YubiKey.h keys/drivers/YubiKeyStub.cpp) endif() if(WITH_XC_NETWORKING) - list(APPEND keepassx_SOURCES - core/HibpDownloader.cpp - core/NetworkManager.cpp + list(APPEND gui_SOURCES + networking/HibpDownloader.cpp + networking/NetworkManager.cpp + networking/UpdateChecker.cpp gui/UpdateCheckDialog.cpp gui/IconDownloader.cpp - gui/IconDownloaderDialog.cpp - updatecheck/UpdateChecker.cpp) -endif() - -if(APPLE) - list(APPEND keepassx_SOURCES touchid/TouchID.mm) - # TODO: Remove -Wno-error once deprecation warnings have been resolved. - set_source_files_properties(touchid/TouchID.mm PROPERTY COMPILE_FLAGS "-Wno-old-style-cast") + gui/IconDownloaderDialog.cpp) endif() configure_file(config-keepassx.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config-keepassx.h) configure_file(git-info.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/git-info.h) -add_library(autotype STATIC ${autotype_SOURCES}) -target_link_libraries(autotype Qt5::Core Qt5::Widgets) - -add_library(keepassx_core STATIC ${keepassx_SOURCES}) - -set_target_properties(keepassx_core PROPERTIES COMPILE_DEFINITIONS KEEPASSX_BUILDING_CORE) -target_link_libraries(keepassx_core - autotype - ${keepassxcbrowser_LIB} +# Core Library Definition +add_library(keepassxc_core STATIC ${core_SOURCES}) +set_target_properties(keepassxc_core PROPERTIES COMPILE_DEFINITIONS KEEPASSX_BUILDING_CORE) +target_link_libraries(keepassxc_core ${qrcode_LIB} - ${fdosecrets_LIB} Qt5::Core Qt5::Concurrent - Qt5::Network - Qt5::Widgets ${BOTAN_LIBRARIES} ${PCSC_LIBRARIES} ${ZXCVBN_LIBRARIES} ${ZLIB_LIBRARIES} ${MINIZIP_LIBRARIES} ${ARGON2_LIBRARIES} - ${thirdparty_LIBRARIES} - ) + ${KEYUTILS_LIBRARIES} + ${thirdparty_LIBRARIES}) -if(WITH_XC_SSHAGENT) - target_link_libraries(keepassx_core sshagent) -endif() -if(WITH_XC_KEESHARE) - target_link_libraries(keepassx_core keeshare) -endif() +# GUI Library Definition +add_library(keepassxc_gui STATIC ${gui_SOURCES}) +set_target_properties(keepassxc_gui PROPERTIES COMPILE_DEFINITIONS KEEPASSX_BUILDING_CORE) +target_link_libraries(keepassxc_gui + keepassxc_core + Qt5::Network + Qt5::Widgets + autotype + ${browser_LIB} + ${fdosecrets_LIB} + ${keeshare_LIB} + ${sshagent_LIB}) if(APPLE) - target_link_libraries(keepassx_core "-framework Foundation -framework AppKit -framework Carbon -framework Security -framework LocalAuthentication") + target_link_libraries(keepassxc_gui "-framework Foundation -framework AppKit -framework Carbon -framework Security -framework LocalAuthentication -framework ScreenCaptureKit") if(Qt5MacExtras_FOUND) - target_link_libraries(keepassx_core Qt5::MacExtras) + target_link_libraries(keepassxc_gui Qt5::MacExtras) endif() endif() if(HAIKU) - target_link_libraries(keepassx_core network) + target_link_libraries(keepassxc_gui network) endif() if(UNIX AND NOT APPLE) - target_link_libraries(keepassx_core Qt5::DBus ${LIBUSB_LIBRARIES}) + target_link_libraries(keepassxc_core Qt5::DBus ${LIBUSB_LIBRARIES}) if(WITH_XC_X11) - target_link_libraries(keepassx_core Qt5::X11Extras X11) + target_link_libraries(keepassxc_gui Qt5::X11Extras X11) endif() include_directories(${Qt5Gui_PRIVATE_INCLUDE_DIRS}) endif() if(WIN32) - target_link_libraries(keepassx_core Wtsapi32.lib Ws2_32.lib) + target_link_libraries(keepassxc_gui Wtsapi32.lib Ws2_32.lib) if (MSVC) - target_link_libraries(keepassx_core WindowsApp.lib) + target_link_libraries(keepassxc_gui WindowsApp.lib) endif() endif() +# Main Executable Definition if(WIN32) include(GenerateProductVersion) generate_product_version( - WIN32_ProductVersionFiles + WIN32_ResourceFiles NAME "KeePassXC" COMPANY_NAME "KeePassXC Team" VERSION_MAJOR ${KEEPASSXC_VERSION_MAJOR} VERSION_MINOR ${KEEPASSXC_VERSION_MINOR} VERSION_PATCH ${KEEPASSXC_VERSION_PATCH} ) + list(APPEND WIN32_ResourceFiles "${CMAKE_SOURCE_DIR}/share/windows/icon.rc") endif() -add_executable(${PROGNAME} WIN32 ${keepassx_SOURCES_MAINEXE} ${WIN32_ProductVersionFiles}) -target_link_libraries(${PROGNAME} keepassx_core) - +add_executable(${PROGNAME} WIN32 main.cpp ${WIN32_ResourceFiles}) +target_link_libraries(${PROGNAME} keepassxc_gui) set_target_properties(${PROGNAME} PROPERTIES ENABLE_EXPORTS ON) +# macOS App Bundle if(APPLE AND WITH_APP_BUNDLE) install(FILES ${CMAKE_SOURCE_DIR}/share/macosx/embedded.provisionprofile DESTINATION ${BUNDLE_INSTALL_DIR}) configure_file(${CMAKE_SOURCE_DIR}/share/macosx/Info.plist.cmake ${CMAKE_CURRENT_BINARY_DIR}/Info.plist) @@ -448,6 +466,7 @@ install(TARGETS ${PROGNAME} BUNDLE DESTINATION . COMPONENT Runtime RUNTIME DESTINATION ${BIN_INSTALL_DIR} COMPONENT Runtime) +# Windows Installer Definition if(WIN32) if(${CMAKE_SIZEOF_VOID_P} EQUAL "8") set(OUTPUT_FILE_POSTFIX "Win64") @@ -559,5 +578,5 @@ if(WIN32) endif() # The install commands in this subdirectory will be executed after all the install commands in the -# current scope are ran. It is required for correct functtioning of macdeployqt. +# current scope are ran. It is required for correct functioning of macdeployqt. add_subdirectory(post_install) diff --git a/src/autotype/AutoType.cpp b/src/autotype/AutoType.cpp index ae53efa6e..c42333fba 100644 --- a/src/autotype/AutoType.cpp +++ b/src/autotype/AutoType.cpp @@ -29,6 +29,7 @@ #include "autotype/AutoTypePlatformPlugin.h" #include "autotype/AutoTypeSelectDialog.h" #include "autotype/PickcharsDialog.h" +#include "core/Global.h" #include "core/Resources.h" #include "core/Tools.h" #include "gui/MainWindow.h" @@ -152,6 +153,7 @@ AutoType::AutoType(QObject* parent, bool test) #endif } + connect(this, SIGNAL(autotypeFinished()), SLOT(resetAutoTypeState())); connect(qApp, SIGNAL(aboutToQuit()), SLOT(unloadPlugin())); } @@ -226,7 +228,7 @@ void AutoType::createTestInstance() QStringList AutoType::windowTitles() { if (!m_plugin) { - return QStringList(); + return {}; } return m_plugin->windowTitles(); @@ -352,14 +354,13 @@ void AutoType::executeAutoTypeActions(const Entry* entry, } } - resetAutoTypeState(); m_inAutoType.unlock(); emit autotypeFinished(); } /** * Single Autotype entry-point function - * Look up the Auto-Type sequence for the given entry then perfom Auto-Type in the active window + * Look up the Auto-Type sequence for the given entry then perform Auto-Type in the active window */ void AutoType::performAutoType(const Entry* entry) { @@ -375,7 +376,7 @@ void AutoType::performAutoType(const Entry* entry) /** * Extra Autotype entry-point function - * Perfom Auto-Type of the directly specified sequence in the active window + * Perform Auto-Type of the directly specified sequence in the active window */ void AutoType::performAutoTypeWithSequence(const Entry* entry, const QString& sequence) { @@ -433,38 +434,33 @@ void AutoType::startGlobalAutoType(const QString& search) */ void AutoType::performGlobalAutoType(const QList>& dbList, const QString& search) { - if (!m_plugin) { - return; - } - - if (!m_inGlobalAutoTypeDialog.tryLock()) { - return; - } - - if (m_windowTitleForGlobal.isEmpty()) { - m_inGlobalAutoTypeDialog.unlock(); + if (!m_plugin || !m_inGlobalAutoTypeDialog.tryLock()) { return; } QList matchList; - bool hideExpired = config()->get(Config::AutoTypeHideExpiredEntry).toBool(); + // Generate entry/sequence match list if there is a valid window title + if (!m_windowTitleForGlobal.isEmpty()) { + bool hideExpired = config()->get(Config::AutoTypeHideExpiredEntry).toBool(); + for (const auto& db : dbList) { + const QList dbEntries = db->rootGroup()->entriesRecursive(); + for (auto entry : dbEntries) { + auto group = entry->group(); + if (!group || !group->resolveAutoTypeEnabled() || !entry->autoTypeEnabled()) { + continue; + } - for (const auto& db : dbList) { - const QList dbEntries = db->rootGroup()->entriesRecursive(); - for (auto entry : dbEntries) { - auto group = entry->group(); - if (!group || !group->resolveAutoTypeEnabled() || !entry->autoTypeEnabled()) { - continue; - } - - if (hideExpired && entry->isExpired()) { - continue; - } - auto sequences = entry->autoTypeSequences(m_windowTitleForGlobal).toSet(); - for (const auto& sequence : sequences) { - matchList << AutoTypeMatch(entry, sequence); + if (hideExpired && entry->isExpired()) { + continue; + } + const QSet sequences = Tools::asSet(entry->autoTypeSequences(m_windowTitleForGlobal)); + for (const auto& sequence : sequences) { + matchList << AutoTypeMatch(entry, sequence); + } } } + } else { + qWarning() << "Auto-Type: Window title was empty from the operating system"; } // Show the selection dialog if we always ask, have multiple matches, or no matches @@ -492,11 +488,9 @@ void AutoType::performGlobalAutoType(const QList>& dbLi m_windowForGlobal, virtualMode ? AutoTypeExecutor::Mode::VIRTUAL : AutoTypeExecutor::Mode::NORMAL); - resetAutoTypeState(); }); connect(selectDialog, &QDialog::rejected, this, [this] { restoreWindowState(); - resetAutoTypeState(); emit autotypeFinished(); }); @@ -510,10 +504,8 @@ void AutoType::performGlobalAutoType(const QList>& dbLi } else if (!matchList.isEmpty()) { // Only one match and not asking, do it! executeAutoTypeActions(matchList.first().first, matchList.first().second, m_windowForGlobal); - resetAutoTypeState(); } else { // We should never get here - resetAutoTypeState(); emit autotypeFinished(); } } @@ -645,10 +637,16 @@ AutoType::parseSequence(const QString& entrySequence, const Entry* entry, QStrin // Platform-specific field clearing actions << QSharedPointer::create(); } else if (placeholder == "totp") { - // Entry totp (requires special handling) - QString totp = entry->totp(); - for (const auto& ch : totp) { - actions << QSharedPointer::create(ch); + if (entry->hasValidTotp()) { + // Entry totp (requires special handling) + QString totp = entry->totp(); + for (const auto& ch : totp) { + actions << QSharedPointer::create(ch); + } + } else if (entry->hasTotp()) { + // Entry has TOTP configured but invalid settings + error = tr("Entry has invalid TOTP settings"); + return {}; } } else if (placeholder.startsWith("pickchars")) { // Reset to the original capture to preserve case @@ -688,74 +686,23 @@ AutoType::parseSequence(const QString& entrySequence, const Entry* entry, QStrin } else if (placeholder.startsWith("t-conv:")) { // Reset to the original capture to preserve case placeholder = match.captured(3); - placeholder.replace("t-conv:", "", Qt::CaseInsensitive); - if (!placeholder.isEmpty()) { - auto sep = placeholder[0]; - auto parts = placeholder.split(sep); - if (parts.size() >= 4) { - auto resolved = entry->resolveMultiplePlaceholders(parts[1]); - auto type = parts[2].toLower(); - - if (type == "base64") { - resolved = resolved.toUtf8().toBase64(); - } else if (type == "hex") { - resolved = resolved.toUtf8().toHex(); - } else if (type == "uri") { - resolved = QUrl::toPercentEncoding(resolved.toUtf8()); - } else if (type == "uri-dec") { - resolved = QUrl::fromPercentEncoding(resolved.toUtf8()); - } else if (type.startsWith("u")) { - resolved = resolved.toUpper(); - } else if (type.startsWith("l")) { - resolved = resolved.toLower(); - } else { - error = tr("Invalid conversion type: %1").arg(type); - return {}; - } - for (const QChar& ch : resolved) { - actions << QSharedPointer::create(ch); - } - } else { - error = tr("Invalid conversion syntax: %1").arg(fullPlaceholder); - return {}; - } - } else { - error = tr("Invalid conversion syntax: %1").arg(fullPlaceholder); + auto resolved = entry->resolveConversionPlaceholder(placeholder, &error); + if (!error.isEmpty()) { return {}; } + for (const QChar& ch : resolved) { + actions << QSharedPointer::create(ch); + } } else if (placeholder.startsWith("t-replace-rx:")) { // Reset to the original capture to preserve case placeholder = match.captured(3); - placeholder.replace("t-replace-rx:", "", Qt::CaseInsensitive); - if (!placeholder.isEmpty()) { - auto sep = placeholder[0]; - auto parts = placeholder.split(sep); - if (parts.size() >= 5) { - auto resolvedText = entry->resolveMultiplePlaceholders(parts[1]); - auto resolvedSearch = entry->resolveMultiplePlaceholders(parts[2]); - auto resolvedReplace = entry->resolveMultiplePlaceholders(parts[3]); - // Replace $ with \\ to support Qt substitutions - resolvedReplace.replace(QRegularExpression(R"(\$(\d+))"), R"(\\1)"); - - auto searchRegex = QRegularExpression(resolvedSearch); - if (!searchRegex.isValid()) { - error = tr("Invalid regular expression syntax %1\n%2") - .arg(resolvedSearch, searchRegex.errorString()); - return {}; - } - - auto resolved = resolvedText.replace(searchRegex, resolvedReplace); - for (const QChar& ch : resolved) { - actions << QSharedPointer::create(ch); - } - } else { - error = tr("Invalid conversion syntax: %1").arg(fullPlaceholder); - return {}; - } - } else { - error = tr("Invalid conversion syntax: %1").arg(fullPlaceholder); + auto resolved = entry->resolveRegexPlaceholder(placeholder, &error); + if (!error.isEmpty()) { return {}; } + for (const QChar& ch : resolved) { + actions << QSharedPointer::create(ch); + } } else if (placeholder.startsWith("mode=")) { auto mode = AutoTypeExecutor::Mode::NORMAL; if (placeholder.endsWith("virtual")) { diff --git a/src/autotype/AutoType.h b/src/autotype/AutoType.h index 17264dd68..4708a7093 100644 --- a/src/autotype/AutoType.h +++ b/src/autotype/AutoType.h @@ -66,6 +66,7 @@ signals: private slots: void startGlobalAutoType(const QString& search); void unloadPlugin(); + void resetAutoTypeState(); private: enum WindowState @@ -83,7 +84,6 @@ private: WId window = 0, AutoTypeExecutor::Mode mode = AutoTypeExecutor::Mode::NORMAL); void restoreWindowState(); - void resetAutoTypeState(); static QList> parseSequence(const QString& entrySequence, const Entry* entry, QString& error, bool syntaxOnly = false); diff --git a/src/autotype/AutoTypeAction.h b/src/autotype/AutoTypeAction.h index 082d0aea7..f68917f8f 100644 --- a/src/autotype/AutoTypeAction.h +++ b/src/autotype/AutoTypeAction.h @@ -38,17 +38,17 @@ public: static Result Ok() { - return Result(true, false, QString()); + return {true, false, QString()}; } static Result Retry(const QString& error) { - return Result(false, true, error); + return {false, true, error}; } static Result Failed(const QString& error) { - return Result(false, false, error); + return {false, false, error}; } bool isOk() const diff --git a/src/autotype/AutoTypePlatformPlugin.h b/src/autotype/AutoTypePlatformPlugin.h index 7154dcdd7..1e1e7b846 100644 --- a/src/autotype/AutoTypePlatformPlugin.h +++ b/src/autotype/AutoTypePlatformPlugin.h @@ -25,9 +25,7 @@ class AutoTypePlatformInterface { public: - virtual ~AutoTypePlatformInterface() - { - } + virtual ~AutoTypePlatformInterface() = default; virtual bool isAvailable() = 0; virtual QStringList windowTitles() = 0; virtual WId activeWindow() = 0; diff --git a/src/autotype/AutoTypeSelectDialog.cpp b/src/autotype/AutoTypeSelectDialog.cpp index 4e31b61d0..d06eaa1c3 100644 --- a/src/autotype/AutoTypeSelectDialog.cpp +++ b/src/autotype/AutoTypeSelectDialog.cpp @@ -21,12 +21,8 @@ #include #include -#include -#if QT_VERSION >= QT_VERSION_CHECK(5, 10, 0) #include -#else -#include -#endif +#include #include "core/Config.h" #include "core/Database.h" @@ -89,12 +85,14 @@ AutoTypeSelectDialog::AutoTypeSelectDialog(QWidget* parent) connect(m_ui->action, &QToolButton::clicked, this, &AutoTypeSelectDialog::activateCurrentMatch); connect(m_ui->cancelButton, SIGNAL(clicked()), SLOT(reject())); + + auto sortColumn = config()->get(Config::AutoTypeDialogSortColumn).toInt(); + auto sortOrder = config()->get(Config::AutoTypeDialogSortOrder).toInt(); + m_ui->view->sortByColumn(sortColumn, sortOrder == 0 ? Qt::AscendingOrder : Qt::DescendingOrder); } // Required for QScopedPointer -AutoTypeSelectDialog::~AutoTypeSelectDialog() -{ -} +AutoTypeSelectDialog::~AutoTypeSelectDialog() = default; void AutoTypeSelectDialog::setMatches(const QList& matches, const QList>& dbs, @@ -266,7 +264,7 @@ void AutoTypeSelectDialog::updateActionMenu(const AutoTypeMatch& match) bool hasUsername = !match.first->username().isEmpty(); bool hasPassword = !match.first->password().isEmpty(); - bool hasTotp = match.first->hasTotp(); + bool hasTotp = match.first->hasValidTotp(); for (auto action : m_actionMenu->actions()) { auto prop = action->property(MENU_FIELD_PROP_NAME); @@ -326,7 +324,7 @@ void AutoTypeSelectDialog::buildActionMenu() submitAutoTypeMatch(match); }); -#ifdef Q_OS_WIN +#if defined(Q_OS_WIN) || defined(Q_OS_MAC) auto typeVirtualAction = new QAction(icons()->icon("auto-type"), tr("Use Virtual Keyboard"), nullptr); m_actionMenu->insertAction(copyUsernameAction, typeVirtualAction); typeVirtualAction->setShortcut(Qt::CTRL + Qt::Key_4); @@ -336,17 +334,7 @@ void AutoTypeSelectDialog::buildActionMenu() }); #endif -#if QT_VERSION >= QT_VERSION_CHECK(5, 10, 0) - // Qt 5.10 introduced a new "feature" to hide shortcuts in context menus - // Unfortunately, Qt::AA_DontShowShortcutsInContextMenus is broken, have to manually enable them - typeUsernameAction->setShortcutVisibleInContextMenu(true); - typePasswordAction->setShortcutVisibleInContextMenu(true); - typeTotpAction->setShortcutVisibleInContextMenu(true); -#ifdef Q_OS_WIN - typeVirtualAction->setShortcutVisibleInContextMenu(true); -#endif -#endif - + copyUsernameAction->setShortcut(Qt::CTRL + Qt::SHIFT + Qt::Key_1); copyUsernameAction->setProperty(MENU_FIELD_PROP_NAME, MENU_FIELD::USERNAME); connect(copyUsernameAction, &QAction::triggered, this, [&] { auto entry = m_ui->view->currentMatch().first; @@ -356,6 +344,7 @@ void AutoTypeSelectDialog::buildActionMenu() } }); + copyPasswordAction->setShortcut(Qt::CTRL + Qt::SHIFT + Qt::Key_2); copyPasswordAction->setProperty(MENU_FIELD_PROP_NAME, MENU_FIELD::PASSWORD); connect(copyPasswordAction, &QAction::triggered, this, [&] { auto entry = m_ui->view->currentMatch().first; @@ -365,6 +354,7 @@ void AutoTypeSelectDialog::buildActionMenu() } }); + copyTotpAction->setShortcut(Qt::CTRL + Qt::SHIFT + Qt::Key_3); copyTotpAction->setProperty(MENU_FIELD_PROP_NAME, MENU_FIELD::TOTP); connect(copyTotpAction, &QAction::triggered, this, [&] { auto entry = m_ui->view->currentMatch().first; @@ -373,22 +363,30 @@ void AutoTypeSelectDialog::buildActionMenu() reject(); } }); + + // Qt 5.10 introduced a new "feature" to hide shortcuts in context menus + // Unfortunately, Qt::AA_DontShowShortcutsInContextMenus is broken, have to manually enable them + typeUsernameAction->setShortcutVisibleInContextMenu(true); + typePasswordAction->setShortcutVisibleInContextMenu(true); + typeTotpAction->setShortcutVisibleInContextMenu(true); +#if defined(Q_OS_WIN) || defined(Q_OS_MAC) + typeVirtualAction->setShortcutVisibleInContextMenu(true); +#endif + copyUsernameAction->setShortcutVisibleInContextMenu(true); + copyPasswordAction->setShortcutVisibleInContextMenu(true); + copyTotpAction->setShortcutVisibleInContextMenu(true); } void AutoTypeSelectDialog::showEvent(QShowEvent* event) { QDialog::showEvent(event); -#if QT_VERSION >= QT_VERSION_CHECK(5, 10, 0) auto screen = QApplication::screenAt(QCursor::pos()); if (!screen) { // screenAt can return a nullptr, default to the primary screen screen = QApplication::primaryScreen(); } QRect screenGeometry = screen->availableGeometry(); -#else - QRect screenGeometry = QApplication::desktop()->availableGeometry(QCursor::pos()); -#endif // Resize to last used size QSize size = config()->get(Config::GUI_AutoTypeSelectDialogSize).toSize(); @@ -403,6 +401,8 @@ void AutoTypeSelectDialog::showEvent(QShowEvent* event) void AutoTypeSelectDialog::hideEvent(QHideEvent* event) { config()->set(Config::GUI_AutoTypeSelectDialogSize, size()); + config()->set(Config::AutoTypeDialogSortColumn, m_ui->view->horizontalHeader()->sortIndicatorSection()); + config()->set(Config::AutoTypeDialogSortOrder, m_ui->view->horizontalHeader()->sortIndicatorOrder()); if (!m_accepted) { emit rejected(); } diff --git a/src/autotype/PickcharsDialog.cpp b/src/autotype/PickcharsDialog.cpp index 798f2e228..54ef34b5f 100644 --- a/src/autotype/PickcharsDialog.cpp +++ b/src/autotype/PickcharsDialog.cpp @@ -21,12 +21,8 @@ #include "gui/Icons.h" #include -#include -#if QT_VERSION >= QT_VERSION_CHECK(5, 10, 0) #include -#else -#include -#endif +#include PickcharsDialog::PickcharsDialog(const QString& string, QWidget* parent) : QDialog(parent) @@ -157,15 +153,11 @@ void PickcharsDialog::showEvent(QShowEvent* event) QDialog::showEvent(event); // Center on active screen -#if QT_VERSION >= QT_VERSION_CHECK(5, 10, 0) auto screen = QApplication::screenAt(QCursor::pos()); if (!screen) { // screenAt can return a nullptr, default to the primary screen screen = QApplication::primaryScreen(); } QRect screenGeometry = screen->availableGeometry(); -#else - QRect screenGeometry = QApplication::desktop()->availableGeometry(QCursor::pos()); -#endif move(screenGeometry.center().x() - (size().width() / 2), screenGeometry.center().y() - (size().height() / 2)); } diff --git a/src/autotype/mac/AutoTypeMac.cpp b/src/autotype/mac/AutoTypeMac.cpp index 815deeecc..05a5d41de 100644 --- a/src/autotype/mac/AutoTypeMac.cpp +++ b/src/autotype/mac/AutoTypeMac.cpp @@ -250,6 +250,10 @@ AutoTypeAction::Result AutoTypeExecutorMac::execType(const AutoTypeKey* action) int ch = action->character.toUpper().toLatin1(); m_platform->sendKey(static_cast(ch), true, action->modifiers); m_platform->sendKey(static_cast(ch), false, action->modifiers); + } else if (mode == Mode::VIRTUAL) { + int ch = action->character.toLatin1(); + m_platform->sendKey(static_cast(ch), true, action->modifiers); + m_platform->sendKey(static_cast(ch), false, action->modifiers); } else { m_platform->sendChar(action->character, true); m_platform->sendChar(action->character, false); diff --git a/src/autotype/mac/CMakeLists.txt b/src/autotype/mac/CMakeLists.txt index e0df901fd..ae1f5187f 100644 --- a/src/autotype/mac/CMakeLists.txt +++ b/src/autotype/mac/CMakeLists.txt @@ -1,7 +1,7 @@ set(autotype_mac_SOURCES AutoTypeMac.cpp) add_library(keepassxc-autotype-cocoa MODULE ${autotype_mac_SOURCES}) -set_target_properties(keepassxc-autotype-cocoa PROPERTIES LINK_FLAGS "-framework Foundation -framework AppKit -framework Carbon") +set_target_properties(keepassxc-autotype-cocoa PROPERTIES LINK_FLAGS "-framework Foundation -framework AppKit -framework Carbon -framework ScreenCaptureKit") target_link_libraries(keepassxc-autotype-cocoa ${PROGNAME} Qt5::Core Qt5::Widgets) install(TARGETS keepassxc-autotype-cocoa diff --git a/src/autotype/test/AutoTypeTest.cpp b/src/autotype/test/AutoTypeTest.cpp index 69c71a53c..641b9502a 100644 --- a/src/autotype/test/AutoTypeTest.cpp +++ b/src/autotype/test/AutoTypeTest.cpp @@ -29,7 +29,7 @@ QString AutoTypePlatformTest::keyToString(Qt::Key key) QStringList AutoTypePlatformTest::windowTitles() { - return QStringList(); + return {}; } WId AutoTypePlatformTest::activeWindow() diff --git a/src/autotype/test/AutoTypeTestInterface.h b/src/autotype/test/AutoTypeTestInterface.h index 7681f2ecb..8b1b7f9ad 100644 --- a/src/autotype/test/AutoTypeTestInterface.h +++ b/src/autotype/test/AutoTypeTestInterface.h @@ -23,9 +23,7 @@ class AutoTypeTestInterface { public: - virtual ~AutoTypeTestInterface() - { - } + virtual ~AutoTypeTestInterface() = default; virtual void setActiveWindowTitle(const QString& title) = 0; virtual QString actionChars() = 0; diff --git a/src/autotype/test/CMakeLists.txt b/src/autotype/test/CMakeLists.txt index 453e36af5..e27f2b1d9 100644 --- a/src/autotype/test/CMakeLists.txt +++ b/src/autotype/test/CMakeLists.txt @@ -1,4 +1,4 @@ set(autotype_test_SOURCES AutoTypeTest.cpp) add_library(keepassxc-autotype-test MODULE ${autotype_test_SOURCES}) -target_link_libraries(keepassxc-autotype-test keepassx_core ${autotype_LIB} Qt5::Core Qt5::Widgets) +target_link_libraries(keepassxc-autotype-test keepassxc_gui ${autotype_LIB} Qt5::Core Qt5::Widgets) diff --git a/src/autotype/windows/CMakeLists.txt b/src/autotype/windows/CMakeLists.txt index 33bd54c58..5b9cbecff 100644 --- a/src/autotype/windows/CMakeLists.txt +++ b/src/autotype/windows/CMakeLists.txt @@ -1,7 +1,7 @@ set(autotype_win_SOURCES AutoTypeWindows.cpp) add_library(keepassxc-autotype-windows MODULE ${autotype_win_SOURCES}) -target_link_libraries(keepassxc-autotype-windows keepassx_core ${autotype_LIB} Qt5::Core Qt5::Widgets) +target_link_libraries(keepassxc-autotype-windows keepassxc_gui ${autotype_LIB} Qt5::Core Qt5::Widgets) install(TARGETS keepassxc-autotype-windows BUNDLE DESTINATION . COMPONENT Runtime LIBRARY DESTINATION ${PLUGIN_INSTALL_DIR} COMPONENT Runtime) diff --git a/src/autotype/xcb/AutoTypeXCB.cpp b/src/autotype/xcb/AutoTypeXCB.cpp index e51b53887..af9c463ee 100644 --- a/src/autotype/xcb/AutoTypeXCB.cpp +++ b/src/autotype/xcb/AutoTypeXCB.cpp @@ -50,14 +50,11 @@ AutoTypePlatformX11::AutoTypePlatformX11() m_atomTransientFor = XInternAtom(m_dpy, "WM_TRANSIENT_FOR", True); m_atomWindow = XInternAtom(m_dpy, "WINDOW", True); - m_classBlacklist << "desktop_window" - << "gnome-panel"; // Gnome - m_classBlacklist << "kdesktop" - << "kicker"; // KDE 3 + m_classBlacklist << "desktop_window" << "gnome-panel"; // Gnome + m_classBlacklist << "kdesktop" << "kicker"; // KDE 3 m_classBlacklist << "Plasma"; // KDE 4 m_classBlacklist << "plasmashell"; // KDE 5 - m_classBlacklist << "xfdesktop" - << "xfce4-panel"; // Xfce 4 + m_classBlacklist << "xfdesktop" << "xfce4-panel"; // Xfce 4 m_xkb = nullptr; @@ -184,17 +181,17 @@ QString AutoTypePlatformX11::windowTitle(Window window, bool useBlacklist) if (useBlacklist && !title.isEmpty()) { if (window == m_rootWindow) { - return QString(); + return {}; } QString className = windowClassName(window); if (m_classBlacklist.contains(className)) { - return QString(); + return {}; } QList keepassxWindows = widgetsToX11Windows(QApplication::topLevelWidgets()); if (keepassxWindows.contains(window)) { - return QString(); + return {}; } } diff --git a/src/autotype/xcb/CMakeLists.txt b/src/autotype/xcb/CMakeLists.txt index 0704de639..f14017f63 100644 --- a/src/autotype/xcb/CMakeLists.txt +++ b/src/autotype/xcb/CMakeLists.txt @@ -3,7 +3,7 @@ include_directories(SYSTEM ${X11_X11_INCLUDE_PATH}) set(autotype_XCB_SOURCES AutoTypeXCB.cpp) add_library(keepassxc-autotype-xcb MODULE ${autotype_XCB_SOURCES}) -target_link_libraries(keepassxc-autotype-xcb keepassx_core Qt5::Core Qt5::Widgets Qt5::X11Extras ${X11_X11_LIB} ${X11_Xi_LIB} ${X11_XTest_LIB}) +target_link_libraries(keepassxc-autotype-xcb keepassxc_gui Qt5::Core Qt5::Widgets Qt5::X11Extras ${X11_X11_LIB} ${X11_Xi_LIB} ${X11_XTest_LIB}) install(TARGETS keepassxc-autotype-xcb BUNDLE DESTINATION . COMPONENT Runtime LIBRARY DESTINATION ${PLUGIN_INSTALL_DIR} COMPONENT Runtime) diff --git a/src/browser/BrowserAccessControlDialog.cpp b/src/browser/BrowserAccessControlDialog.cpp index 3fce10c5c..b3d9944d3 100644 --- a/src/browser/BrowserAccessControlDialog.cpp +++ b/src/browser/BrowserAccessControlDialog.cpp @@ -1,6 +1,6 @@ /* + * Copyright (C) 2023 KeePassXC Team * Copyright (C) 2013 Francois Ferrand - * Copyright (C) 2022 KeePassXC Team * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -21,12 +21,11 @@ #include #include "core/Entry.h" -#include +#include "gui/Icons.h" BrowserAccessControlDialog::BrowserAccessControlDialog(QWidget* parent) : QDialog(parent) , m_ui(new Ui::BrowserAccessControlDialog()) - , m_entriesAccepted(false) { setWindowFlags(windowFlags() | Qt::WindowStaysOnTopHint); @@ -34,13 +33,22 @@ BrowserAccessControlDialog::BrowserAccessControlDialog(QWidget* parent) connect(m_ui->allowButton, SIGNAL(clicked()), SLOT(accept())); connect(m_ui->denyButton, SIGNAL(clicked()), SLOT(reject())); + connect(m_ui->itemsTable, SIGNAL(cellDoubleClicked(int, int)), this, SLOT(accept())); + connect(m_ui->itemsTable->selectionModel(), + SIGNAL(selectionChanged(QItemSelection, QItemSelection)), + this, + SLOT(selectionChanged())); + connect(m_ui->itemsTable, SIGNAL(acceptSelections()), SLOT(accept())); + connect(m_ui->itemsTable, SIGNAL(focusInWithoutSelections()), this, SLOT(selectionChanged())); } BrowserAccessControlDialog::~BrowserAccessControlDialog() { } -void BrowserAccessControlDialog::setItems(const QList& items, const QString& urlString, bool httpAuth) +void BrowserAccessControlDialog::setEntries(const QList& entriesToConfirm, + const QString& urlString, + bool httpAuth) { QUrl url(urlString); m_ui->siteLabel->setText(m_ui->siteLabel->text().arg( @@ -49,60 +57,115 @@ void BrowserAccessControlDialog::setItems(const QList& items, const QStr m_ui->rememberDecisionCheckBox->setVisible(!httpAuth); m_ui->rememberDecisionCheckBox->setChecked(false); - m_ui->itemsTable->setRowCount(items.count()); + m_ui->itemsTable->setRowCount(entriesToConfirm.count()); m_ui->itemsTable->setColumnCount(2); int row = 0; - for (const auto& entry : items) { - auto item = new QTableWidgetItem(); - item->setText(entry->title() + " - " + entry->username()); - item->setData(Qt::UserRole, row); - item->setCheckState(Qt::Checked); - item->setFlags(item->flags() | Qt::ItemIsUserCheckable); - m_ui->itemsTable->setItem(row, 0, item); - - auto disableButton = new QPushButton(tr("Disable for this site")); - disableButton->setAutoDefault(false); - connect(disableButton, &QAbstractButton::pressed, [&, item] { - emit disableAccess(item); - m_ui->itemsTable->removeRow(item->row()); - if (m_ui->itemsTable->rowCount() == 0) { - reject(); - } - }); - m_ui->itemsTable->setCellWidget(row, 1, disableButton); + for (const auto& entry : entriesToConfirm) { + addEntryToList(entry, row); ++row; } m_ui->itemsTable->resizeColumnsToContents(); m_ui->itemsTable->horizontalHeader()->setSectionResizeMode(0, QHeaderView::Stretch); + m_ui->itemsTable->selectAll(); m_ui->allowButton->setFocus(); } +void BrowserAccessControlDialog::addEntryToList(Entry* entry, int row) +{ + auto item = new QTableWidgetItem(); + item->setText(entry->resolveMultiplePlaceholders(entry->title()) + " - " + + entry->resolveMultiplePlaceholders(entry->username())); + item->setData(Qt::UserRole, row); + item->setFlags(item->flags() | Qt::ItemIsSelectable); + m_ui->itemsTable->setItem(row, 0, item); + + auto disableButton = new QPushButton(); + disableButton->setIcon(icons()->icon("entry-delete")); + disableButton->setToolTip(tr("Disable for this site")); + + connect(disableButton, &QAbstractButton::pressed, [&, item, disableButton] { + auto font = item->font(); + if (item->flags() == Qt::NoItemFlags) { + item->setFlags(Qt::ItemIsEnabled | Qt::ItemIsSelectable); + item->setSelected(true); + + font.setStrikeOut(false); + item->setFont(font); + + disableButton->setIcon(icons()->icon("entry-delete")); + disableButton->setToolTip(tr("Disable for this site")); + m_ui->rememberDecisionCheckBox->setEnabled(true); + } else { + item->setFlags(Qt::NoItemFlags); + item->setSelected(false); + + font.setStrikeOut(true); + item->setFont(font); + + disableButton->setIcon(icons()->icon("entry-restore")); + disableButton->setToolTip(tr("Undo")); + + // Disable Remember checkbox if all items are disabled + auto areAllDisabled = BrowserAccessControlDialog::areAllDisabled(); + m_ui->rememberDecisionCheckBox->setEnabled(!areAllDisabled); + } + }); + + m_ui->itemsTable->setCellWidget(row, 1, disableButton); +} + bool BrowserAccessControlDialog::remember() const { return m_ui->rememberDecisionCheckBox->isChecked(); } -QList BrowserAccessControlDialog::getSelectedEntries() const +QList BrowserAccessControlDialog::getEntries(SelectionType selectionType) const { QList selected; - for (int i = 0; i < m_ui->itemsTable->rowCount(); ++i) { - auto item = m_ui->itemsTable->item(i, 0); - if (item->checkState() == Qt::Checked) { + for (auto& item : getAllItems()) { + // Add to list depending on selection type and item status + if ((selectionType == SelectionType::Selected && item->isSelected()) + || (selectionType == SelectionType::NonSelected && !item->isSelected()) + || (selectionType == SelectionType::Disabled && item->flags() == Qt::NoItemFlags)) { selected.append(item); } } return selected; } -QList BrowserAccessControlDialog::getNonSelectedEntries() const +void BrowserAccessControlDialog::selectionChanged() { - QList notSelected; - for (int i = 0; i < m_ui->itemsTable->rowCount(); ++i) { - auto item = m_ui->itemsTable->item(i, 0); - if (item->checkState() != Qt::Checked) { - notSelected.append(item); + auto selectedRows = m_ui->itemsTable->selectionModel()->selectedRows(); + + m_ui->allowButton->setEnabled(!selectedRows.isEmpty()); + m_ui->allowButton->setDefault(!selectedRows.isEmpty()); + m_ui->allowButton->setAutoDefault(!selectedRows.isEmpty()); + + if (selectedRows.isEmpty()) { + m_ui->allowButton->clearFocus(); + m_ui->denyButton->setFocus(); + } +} + +bool BrowserAccessControlDialog::areAllDisabled() const +{ + auto areAllDisabled = true; + for (const auto& item : getAllItems()) { + if (item->flags() != Qt::NoItemFlags) { + areAllDisabled = false; } } - return notSelected; + + return areAllDisabled; +} + +QList BrowserAccessControlDialog::getAllItems() const +{ + QList items; + for (int i = 0; i < m_ui->itemsTable->rowCount(); ++i) { + auto item = m_ui->itemsTable->item(i, 0); + items.append(item); + } + return items; } diff --git a/src/browser/BrowserAccessControlDialog.h b/src/browser/BrowserAccessControlDialog.h index 946db16d9..3ecf5b506 100644 --- a/src/browser/BrowserAccessControlDialog.h +++ b/src/browser/BrowserAccessControlDialog.h @@ -1,6 +1,6 @@ /* + * Copyright (C) 2023 KeePassXC Team * Copyright (C) 2013 Francois Ferrand - * Copyright (C) 2022 KeePassXC Team * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -29,6 +29,13 @@ namespace Ui class BrowserAccessControlDialog; } +enum SelectionType +{ + Selected, + NonSelected, + Disabled +}; + class BrowserAccessControlDialog : public QDialog { Q_OBJECT @@ -37,20 +44,24 @@ public: explicit BrowserAccessControlDialog(QWidget* parent = nullptr); ~BrowserAccessControlDialog() override; - void setItems(const QList& items, const QString& urlString, bool httpAuth); + void setEntries(const QList& entriesToConfirm, const QString& urlString, bool httpAuth); bool remember() const; - - QList getSelectedEntries() const; - QList getNonSelectedEntries() const; + QList getEntries(SelectionType selectionType) const; signals: void disableAccess(QTableWidgetItem* item); +private slots: + void selectionChanged(); + +private: + void addEntryToList(Entry* entry, int row); + bool areAllDisabled() const; + QList getAllItems() const; + private: QScopedPointer m_ui; QList m_entriesToConfirm; - QList m_allowedEntries; - bool m_entriesAccepted; }; #endif // KEEPASSXC_BROWSERACCESSCONTROLDIALOG_H diff --git a/src/browser/BrowserAccessControlDialog.ui b/src/browser/BrowserAccessControlDialog.ui old mode 100755 new mode 100644 index 4224c1633..63f264311 --- a/src/browser/BrowserAccessControlDialog.ui +++ b/src/browser/BrowserAccessControlDialog.ui @@ -31,7 +31,7 @@ - + QAbstractItemView::NoEditTriggers @@ -39,7 +39,10 @@ false - QAbstractItemView::NoSelection + QAbstractItemView::ExtendedSelection + + + QAbstractItemView::SelectRows false @@ -110,6 +113,19 @@ + + rememberDecisionCheckBox + allowButton + denyButton + + + + CustomTableWidget + QTableWidget +
    browser/CustomTableWidget.h
    + 1 +
    +
    diff --git a/src/browser/BrowserAction.cpp b/src/browser/BrowserAction.cpp index 6e49317a8..67cf7f0df 100644 --- a/src/browser/BrowserAction.cpp +++ b/src/browser/BrowserAction.cpp @@ -108,6 +108,8 @@ QJsonObject BrowserAction::handleAction(QLocalSocket* socket, const QJsonObject& return handleDeleteEntry(json, action); } else if (action.compare(BROWSER_REQUEST_REQUEST_AUTOTYPE) == 0) { return handleGlobalAutoType(json, action); + } else if (action.compare("get-database-entries", Qt::CaseSensitive) == 0) { + return handleGetDatabaseEntries(json, action); #ifdef WITH_XC_BROWSER_PASSKEYS } else if (action.compare(BROWSER_REQUEST_PASSKEYS_GET) == 0) { return handlePasskeysGet(json, action); @@ -387,6 +389,36 @@ QJsonObject BrowserAction::handleGetDatabaseGroups(const QJsonObject& json, cons return buildResponse(action, browserRequest.incrementedNonce, params); } +QJsonObject BrowserAction::handleGetDatabaseEntries(const QJsonObject& json, const QString& action) +{ + if (!m_associated) { + return getErrorReply(action, ERROR_KEEPASS_ASSOCIATION_FAILED); + } + + const auto browserRequest = decodeRequest(json); + if (browserRequest.isEmpty()) { + return getErrorReply(action, ERROR_KEEPASS_CANNOT_DECRYPT_MESSAGE); + } + + const auto command = browserRequest.getString("action"); + if (command.isEmpty() || command.compare("get-database-entries") != 0) { + return getErrorReply(action, ERROR_KEEPASS_INCORRECT_ACTION); + } + + if (!browserSettings()->allowGetDatabaseEntriesRequest()) { + return getErrorReply(action, ERROR_KEEPASS_ACCESS_TO_ALL_ENTRIES_DENIED); + } + + const QJsonArray entries = browserService()->getDatabaseEntries(); + if (entries.isEmpty()) { + return getErrorReply(action, ERROR_KEEPASS_NO_GROUPS_FOUND); + } + + const Parameters params{{"entries", entries}}; + + return buildResponse(action, browserRequest.incrementedNonce, params); +} + QJsonObject BrowserAction::handleCreateNewGroup(const QJsonObject& json, const QString& action) { if (!m_associated) { @@ -547,8 +579,9 @@ QJsonObject BrowserAction::handlePasskeysRegister(const QJsonObject& json, const return getErrorReply(action, ERROR_PASSKEYS_INVALID_URL_PROVIDED); } + const auto groupName = browserRequest.getString("groupName"); const auto keyList = getConnectionKeys(browserRequest); - const auto response = browserService()->showPasskeysRegisterPrompt(publicKey, origin, keyList); + const auto response = browserService()->showPasskeysRegisterPrompt(publicKey, origin, groupName, keyList); const Parameters params{{"response", response}}; return buildResponse(action, browserRequest.incrementedNonce, params); diff --git a/src/browser/BrowserAction.h b/src/browser/BrowserAction.h index f737982f0..5c115f5f1 100644 --- a/src/browser/BrowserAction.h +++ b/src/browser/BrowserAction.h @@ -79,6 +79,7 @@ private: QJsonObject handleSetLogin(const QJsonObject& json, const QString& action); QJsonObject handleLockDatabase(const QJsonObject& json, const QString& action); QJsonObject handleGetDatabaseGroups(const QJsonObject& json, const QString& action); + QJsonObject handleGetDatabaseEntries(const QJsonObject& json, const QString& action); QJsonObject handleCreateNewGroup(const QJsonObject& json, const QString& action); QJsonObject handleGetTotp(const QJsonObject& json, const QString& action); QJsonObject handleDeleteEntry(const QJsonObject& json, const QString& action); diff --git a/src/browser/BrowserEntryConfig.cpp b/src/browser/BrowserEntryConfig.cpp index a5bd3263f..63d3bd16b 100644 --- a/src/browser/BrowserEntryConfig.cpp +++ b/src/browser/BrowserEntryConfig.cpp @@ -19,6 +19,7 @@ #include "BrowserEntryConfig.h" #include "core/Entry.h" +#include "core/Global.h" #include "core/Tools.h" #include @@ -34,22 +35,22 @@ BrowserEntryConfig::BrowserEntryConfig(QObject* parent) QStringList BrowserEntryConfig::allowedHosts() const { - return m_allowedHosts.toList(); + return m_allowedHosts.values(); } void BrowserEntryConfig::setAllowedHosts(const QStringList& allowedHosts) { - m_allowedHosts = allowedHosts.toSet(); + m_allowedHosts = Tools::asSet(allowedHosts); } QStringList BrowserEntryConfig::deniedHosts() const { - return m_deniedHosts.toList(); + return m_deniedHosts.values(); } void BrowserEntryConfig::setDeniedHosts(const QStringList& deniedHosts) { - m_deniedHosts = deniedHosts.toSet(); + m_deniedHosts = Tools::asSet(deniedHosts); } bool BrowserEntryConfig::isAllowed(const QString& host) const diff --git a/src/browser/BrowserEntrySaveDialog.ui b/src/browser/BrowserEntrySaveDialog.ui old mode 100755 new mode 100644 diff --git a/src/browser/BrowserPasskeys.cpp b/src/browser/BrowserPasskeys.cpp index 3e81a25f7..287b42cca 100644 --- a/src/browser/BrowserPasskeys.cpp +++ b/src/browser/BrowserPasskeys.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2024 KeePassXC Team + * Copyright (C) 2025 KeePassXC Team * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -19,6 +19,7 @@ #include "BrowserMessageBuilder.h" #include "BrowserService.h" #include "PasskeyUtils.h" +#include "config-keepassx.h" #include "crypto/Random.h" #include #include @@ -57,17 +58,6 @@ const QString BrowserPasskeys::REQUIREMENT_REQUIRED = QStringLiteral("required") const QString BrowserPasskeys::PASSKEYS_ATTESTATION_DIRECT = QStringLiteral("direct"); const QString BrowserPasskeys::PASSKEYS_ATTESTATION_NONE = QStringLiteral("none"); -const QString BrowserPasskeys::KPEX_PASSKEY_USERNAME = QStringLiteral("KPEX_PASSKEY_USERNAME"); -const QString BrowserPasskeys::KPEX_PASSKEY_CREDENTIAL_ID = QStringLiteral("KPEX_PASSKEY_CREDENTIAL_ID"); - -// For compatibility with StrongBox -const QString BrowserPasskeys::KPEX_PASSKEY_GENERATED_USER_ID = QStringLiteral("KPEX_PASSKEY_GENERATED_USER_ID"); -const QString BrowserPasskeys::KPXC_PASSKEY_USERNAME = QStringLiteral("KPXC_PASSKEY_USERNAME"); - -const QString BrowserPasskeys::KPEX_PASSKEY_PRIVATE_KEY_PEM = QStringLiteral("KPEX_PASSKEY_PRIVATE_KEY_PEM"); -const QString BrowserPasskeys::KPEX_PASSKEY_RELYING_PARTY = QStringLiteral("KPEX_PASSKEY_RELYING_PARTY"); -const QString BrowserPasskeys::KPEX_PASSKEY_USER_HANDLE = QStringLiteral("KPEX_PASSKEY_USER_HANDLE"); - BrowserPasskeys* BrowserPasskeys::instance() { return s_browserPasskeys; @@ -81,7 +71,7 @@ PublicKeyCredential BrowserPasskeys::buildRegisterPublicKeyCredential(const QJso } const auto authenticatorAttachment = credentialCreationOptions["authenticatorAttachment"]; - const auto clientDataJson = credentialCreationOptions["clientDataJSON"].toObject(); + const auto clientDataJson = credentialCreationOptions["clientDataJSON"].toString(); const auto extensions = credentialCreationOptions["extensions"].toString(); const auto credentialId = testingVariables.credentialId.isEmpty() ? browserMessageBuilder()->getRandomBytesAsBase64(ID_BYTES) @@ -102,12 +92,19 @@ PublicKeyCredential BrowserPasskeys::buildRegisterPublicKeyCredential(const QJso return {}; } + // Authenticator data + const auto authenticatorData = buildAuthenticatorData(credentialCreationOptions["rp"]["id"].toString(), extensions); + // Response QJsonObject responseObject; responseObject["attestationObject"] = browserMessageBuilder()->getBase64FromArray(attestationObject); - responseObject["clientDataJSON"] = browserMessageBuilder()->getBase64FromJson(clientDataJson); + responseObject["clientDataJSON"] = browserMessageBuilder()->getBase64FromArray(clientDataJson.toUtf8()); responseObject["clientExtensionResults"] = credentialCreationOptions["clientExtensionResults"]; + // Additions for extension side functions + responseObject["authenticatorData"] = browserMessageBuilder()->getBase64FromArray(authenticatorData); + responseObject["publicKeyAlgorithm"] = alg; + // PublicKeyCredential QJsonObject publicKeyCredential; publicKeyCredential["authenticatorAttachment"] = authenticatorAttachment; @@ -131,9 +128,10 @@ QJsonObject BrowserPasskeys::buildGetPublicKeyCredential(const QJsonObject& asse return {}; } - const auto authenticatorData = buildAuthenticatorData(assertionOptions); - const auto clientDataJson = assertionOptions["clientDataJson"].toObject(); - const auto clientDataArray = QJsonDocument(clientDataJson).toJson(QJsonDocument::Compact); + const auto authenticatorData = + buildAuthenticatorData(assertionOptions["rpId"].toString(), assertionOptions["extensions"].toString()); + const auto clientDataJson = assertionOptions["clientDataJson"].toString(); + const auto clientDataArray = clientDataJson.toUtf8(); const auto signature = buildSignature(authenticatorData, clientDataArray, privateKeyPem); if (signature.isEmpty()) { @@ -142,7 +140,7 @@ QJsonObject BrowserPasskeys::buildGetPublicKeyCredential(const QJsonObject& asse QJsonObject responseObject; responseObject["authenticatorData"] = browserMessageBuilder()->getBase64FromArray(authenticatorData); - responseObject["clientDataJSON"] = browserMessageBuilder()->getBase64FromJson(clientDataJson); + responseObject["clientDataJSON"] = browserMessageBuilder()->getBase64FromArray(clientDataArray); responseObject["clientExtensionResults"] = assertionOptions["clientExtensionResults"]; responseObject["signature"] = browserMessageBuilder()->getBase64FromArray(signature); responseObject["userHandle"] = userHandle; @@ -203,14 +201,13 @@ QByteArray BrowserPasskeys::buildAttestationObject(const QJsonObject& credential } // Build a short version of the attestation object for webauthn.get -QByteArray BrowserPasskeys::buildAuthenticatorData(const QJsonObject& publicKey) +QByteArray BrowserPasskeys::buildAuthenticatorData(const QString& rpId, const QString& extensions) { QByteArray result; - const auto rpIdHash = browserMessageBuilder()->getSha256Hash(publicKey["rpId"].toString()); + const auto rpIdHash = browserMessageBuilder()->getSha256Hash(rpId); result.append(rpIdHash); - const auto extensions = publicKey["extensions"].toString(); const auto flags = setFlagsFromJson(QJsonObject( {{"ED", !extensions.isEmpty()}, {"AT", false}, {"BS", false}, {"BE", false}, {"UV", true}, {"UP", true}})); result.append(flags); @@ -276,7 +273,11 @@ BrowserPasskeys::buildCredentialPrivateKey(int alg, const QString& predefinedFir try { Botan::Ed25519_PrivateKey key(*randomGen()->getRng()); auto publicKey = key.get_public_key(); +#ifdef WITH_XC_BOTAN3 + auto privateKey = key.raw_private_key_bits(); +#else auto privateKey = key.get_private_key(); +#endif firstPart = browserMessageBuilder()->getQByteArray(publicKey.data(), publicKey.size()); secondPart = browserMessageBuilder()->getQByteArray(privateKey.data(), privateKey.size()); diff --git a/src/browser/BrowserPasskeys.h b/src/browser/BrowserPasskeys.h index 0c09e3314..4955654c9 100644 --- a/src/browser/BrowserPasskeys.h +++ b/src/browser/BrowserPasskeys.h @@ -105,21 +105,13 @@ public: static const QString PASSKEYS_ATTESTATION_DIRECT; static const QString PASSKEYS_ATTESTATION_NONE; - static const QString KPXC_PASSKEY_USERNAME; - static const QString KPEX_PASSKEY_USERNAME; - static const QString KPEX_PASSKEY_CREDENTIAL_ID; - static const QString KPEX_PASSKEY_GENERATED_USER_ID; - static const QString KPEX_PASSKEY_PRIVATE_KEY_PEM; - static const QString KPEX_PASSKEY_RELYING_PARTY; - static const QString KPEX_PASSKEY_USER_HANDLE; - private: QByteArray buildAttestationObject(const QJsonObject& credentialCreationOptions, const QString& extensions, const QString& credentialId, const QByteArray& cborEncodedPublicKey, const TestingVariables& predefinedVariables = {}); - QByteArray buildAuthenticatorData(const QJsonObject& publicKey); + QByteArray buildAuthenticatorData(const QString& rpId, const QString& extensions); AttestationKeyPair buildCredentialPrivateKey(int alg, const QString& predefinedFirst = QString(), const QString& predefinedSecond = QString()); diff --git a/src/browser/BrowserPasskeysConfirmationDialog.cpp b/src/browser/BrowserPasskeysConfirmationDialog.cpp index 50bdfbc49..aa0dcc532 100644 --- a/src/browser/BrowserPasskeysConfirmationDialog.cpp +++ b/src/browser/BrowserPasskeysConfirmationDialog.cpp @@ -155,4 +155,4 @@ void BrowserPasskeysConfirmationDialog::updateEntriesToTable(const QList m_ui->credentialsTable->resizeColumnsToContents(); m_ui->credentialsTable->horizontalHeader()->setStretchLastSection(true); -} \ No newline at end of file +} diff --git a/src/browser/BrowserPasskeysConfirmationDialog.ui b/src/browser/BrowserPasskeysConfirmationDialog.ui old mode 100755 new mode 100644 diff --git a/src/browser/BrowserService.cpp b/src/browser/BrowserService.cpp index 91a0fb28b..775868a51 100644 --- a/src/browser/BrowserService.cpp +++ b/src/browser/BrowserService.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2024 KeePassXC Team + * Copyright (C) 2025 KeePassXC Team * Copyright (C) 2017 Sami Vänttinen * Copyright (C) 2013 Francois Ferrand * @@ -24,10 +24,11 @@ #include "BrowserHost.h" #include "BrowserMessageBuilder.h" #include "BrowserSettings.h" +#include "core/EntryAttributes.h" #include "core/Tools.h" -#include "core/UrlTools.h" #include "gui/MainWindow.h" #include "gui/MessageBox.h" +#include "gui/UrlTools.h" #include "gui/osutils/OSUtils.h" #ifdef WITH_XC_BROWSER_PASSKEYS #include "BrowserPasskeys.h" @@ -48,7 +49,9 @@ #include #include #include +#include #include +#include #include const QString BrowserService::KEEPASSXCBROWSER_NAME = QStringLiteral("KeePassXC-Browser Settings"); @@ -57,6 +60,7 @@ static const QString KEEPASSXCBROWSER_GROUP_NAME = QStringLiteral("KeePassXC-Bro static int KEEPASSXCBROWSER_DEFAULT_ICON = 1; #ifdef WITH_XC_BROWSER_PASSKEYS static int KEEPASSXCBROWSER_PASSKEY_ICON = 13; +static const QString PASSKEYS_DEFAULT_GROUP_NAME = QStringLiteral("KeePassXC-Browser Passkeys"); #endif // These are for the settings and password conversion static const QString KEEPASSHTTP_NAME = QStringLiteral("KeePassHttp Settings"); @@ -67,6 +71,7 @@ const QString BrowserService::OPTION_HIDE_ENTRY = QStringLiteral("BrowserHideEnt const QString BrowserService::OPTION_ONLY_HTTP_AUTH = QStringLiteral("BrowserOnlyHttpAuth"); const QString BrowserService::OPTION_NOT_HTTP_AUTH = QStringLiteral("BrowserNotHttpAuth"); const QString BrowserService::OPTION_OMIT_WWW = QStringLiteral("BrowserOmitWww"); +const QString BrowserService::OPTION_RESTRICT_KEY = QStringLiteral("BrowserRestrictKey"); Q_GLOBAL_STATIC(BrowserService, s_browserService); @@ -82,6 +87,10 @@ BrowserService::BrowserService() connect(getMainWindow(), &MainWindow::databaseUnlocked, this, &BrowserService::databaseUnlocked); connect(getMainWindow(), &MainWindow::databaseLocked, this, &BrowserService::databaseLocked); connect(getMainWindow(), &MainWindow::activeDatabaseChanged, this, &BrowserService::activeDatabaseChanged); + connect(getMainWindow(), + &MainWindow::databaseUnlockDialogFinished, + this, + &BrowserService::handleDatabaseUnlockDialogFinished); setEnabled(browserSettings()->isEnabled()); } @@ -227,7 +236,7 @@ QJsonObject BrowserService::getDatabaseGroups() return result; } -QJsonObject BrowserService::createNewGroup(const QString& groupName) +QJsonArray BrowserService::getDatabaseEntries() { auto db = getDatabase(); if (!db) { @@ -239,6 +248,39 @@ QJsonObject BrowserService::createNewGroup(const QString& groupName) return {}; } + QJsonArray entries; + for (const auto& group : rootGroup->groupsRecursive(true)) { + if (group == db->metadata()->recycleBin()) { + continue; + } + + for (const auto& entry : group->entries()) { + QJsonObject jentry; + jentry["title"] = entry->resolveMultiplePlaceholders(entry->title()); + jentry["uuid"] = entry->resolveMultiplePlaceholders(entry->uuidToHex()); + jentry["url"] = entry->resolveMultiplePlaceholders(entry->url()); + entries.push_back(jentry); + } + } + return entries; +} + +QJsonObject BrowserService::createNewGroup(const QString& groupName, bool isPasskeysGroup) +{ + if (groupName.isEmpty()) { + return {}; + } + + auto db = getDatabase(); + if (!db) { + return {}; + } + + Group* rootGroup = db->rootGroup(); + if (!rootGroup) { + return {}; + } + auto group = rootGroup->findGroupByPath(groupName); // Group already exists @@ -278,11 +320,17 @@ QJsonObject BrowserService::createNewGroup(const QString& groupName) QString gName = getGroupName(i); auto tempGroup = rootGroup->findGroupByPath(gName); if (!tempGroup) { - Group* newGroup = new Group(); + auto newGroup = new Group(); newGroup->setName(groups[i]); newGroup->setUuid(QUuid::createUuid()); newGroup->setParent(previousGroup); +#ifdef WITH_XC_BROWSER_PASSKEYS + if (isPasskeysGroup && i == groups.length() - 1) { + newGroup->setIcon(KEEPASSXCBROWSER_PASSKEY_ICON); + } +#endif name = newGroup->name(); + newGroup->setCustomDataTriState(BrowserService::OPTION_HIDE_ENTRY, Group::Disable); uuid = Tools::uuidToHex(newGroup->uuid()); previousGroup = newGroup; continue; @@ -431,25 +479,48 @@ QList BrowserService::confirmEntries(QList& entriesToConfirm, denyEntry(entry, siteHost, formUrl, entryParameters.realm); }); - accessControlDialog.setItems(entriesToConfirm, entryParameters.siteUrl, httpAuth); + accessControlDialog.setEntries(entriesToConfirm, entryParameters.siteUrl, httpAuth); QList allowedEntries; auto ret = accessControlDialog.exec(); - for (auto item : accessControlDialog.getSelectedEntries()) { - auto entry = entriesToConfirm[item->row()]; - if (accessControlDialog.remember()) { - if (ret == QDialog::Accepted) { + auto remember = accessControlDialog.remember(); + + // All are denied + if (ret == QDialog::Rejected && remember) { + for (auto& entry : entriesToConfirm) { + denyEntry(entry, siteHost, formUrl, entryParameters.realm); + } + } + + // Some/all are accepted + if (ret == QDialog::Accepted) { + auto selectedEntries = accessControlDialog.getEntries(SelectionType::Selected); + for (auto& item : selectedEntries) { + auto entry = entriesToConfirm[item->row()]; + allowedEntries.append(entry); + + if (remember) { allowEntry(entry, siteHost, formUrl, entryParameters.realm); - } else { - denyEntry(entry, siteHost, formUrl, entryParameters.realm); } } - if (ret == QDialog::Accepted) { - allowedEntries.append(entry); + // Remembered non-selected entries must be denied + if (remember) { + auto nonSelectedEntries = accessControlDialog.getEntries(SelectionType::NonSelected); + for (auto& item : nonSelectedEntries) { + auto entry = entriesToConfirm[item->row()]; + denyEntry(entry, siteHost, formUrl, entryParameters.realm); + } } } + // Handle disabled entries (returned Accept/Reject status does not matter) + auto disabledEntries = accessControlDialog.getEntries(SelectionType::Disabled); + for (auto& item : disabledEntries) { + auto entry = entriesToConfirm[item->row()]; + denyEntry(entry, siteHost, formUrl, entryParameters.realm); + } + // Re-hide the application if it wasn't visible before hideWindow(); m_dialogActive = false; @@ -462,20 +533,23 @@ void BrowserService::showPasswordGenerator(const KeyPairMessage& keyPairMessage) if (!m_passwordGenerator) { m_passwordGenerator = PasswordGeneratorWidget::popupGenerator(); - connect(m_passwordGenerator.data(), &PasswordGeneratorWidget::closed, m_passwordGenerator.data(), [=] { - if (!m_passwordGenerator->isPasswordGenerated()) { - auto errorMessage = browserMessageBuilder()->getErrorReply("generate-password", - ERROR_KEEPASS_ACTION_CANCELLED_OR_DENIED); - m_browserHost->sendClientMessage(keyPairMessage.socket, errorMessage); - } + connect(m_passwordGenerator.data(), + &PasswordGeneratorWidget::closed, + m_passwordGenerator.data(), + [this, keyPairMessage] { + if (!m_passwordGenerator->isPasswordGenerated()) { + auto errorMessage = browserMessageBuilder()->getErrorReply( + "generate-password", ERROR_KEEPASS_ACTION_CANCELLED_OR_DENIED); + m_browserHost->sendClientMessage(keyPairMessage.socket, errorMessage); + } - QTimer::singleShot(50, this, [&] { hideWindow(); }); - }); + QTimer::singleShot(50, this, [&] { hideWindow(); }); + }); connect(m_passwordGenerator.data(), &PasswordGeneratorWidget::appliedPassword, m_passwordGenerator.data(), - [=](const QString& password) { + [this, keyPairMessage](const QString& password) { const Parameters params{{"password", password}}; m_browserHost->sendClientMessage(keyPairMessage.socket, browserMessageBuilder()->buildResponse("generate-password", @@ -530,7 +604,8 @@ QString BrowserService::storeKey(const QString& key) return {}; } - contains = db->metadata()->customData()->contains(CustomData::BrowserKeyPrefix + id); + contains = + db->metadata()->customData()->contains(CustomData::getKeyWithPrefix(CustomData::BrowserKeyPrefix, id)); if (contains) { dialogResult = MessageBox::warning(m_currentDatabaseWidget, tr("KeePassXC - Overwrite existing key?"), @@ -543,9 +618,9 @@ QString BrowserService::storeKey(const QString& key) } while (contains && dialogResult == MessageBox::Cancel); hideWindow(); - db->metadata()->customData()->set(CustomData::BrowserKeyPrefix + id, key); - db->metadata()->customData()->set(QString("%1_%2").arg(CustomData::Created, id), - Clock::currentDateTime().toString(Qt::SystemLocaleShortDate)); + db->metadata()->customData()->set(CustomData::getKeyWithPrefix(CustomData::BrowserKeyPrefix, id), key); + db->metadata()->customData()->set(CustomData::getKeyWithPrefix(CustomData::Created, id), + QLocale::system().toString(Clock::currentDateTime(), QLocale::ShortFormat)); return id; } @@ -556,13 +631,14 @@ QString BrowserService::getKey(const QString& id) return {}; } - return db->metadata()->customData()->value(CustomData::BrowserKeyPrefix + id); + return db->metadata()->customData()->value(CustomData::getKeyWithPrefix(CustomData::BrowserKeyPrefix, id)); } #ifdef WITH_XC_BROWSER_PASSKEYS // Passkey registration QJsonObject BrowserService::showPasskeysRegisterPrompt(const QJsonObject& publicKeyOptions, const QString& origin, + const QString& groupName, const StringPairList& keyList) { auto db = selectedDatabase(); @@ -634,8 +710,13 @@ QJsonObject BrowserService::showPasskeysRegisterPrompt(const QJsonObject& public publicKeyCredentials.key); } } else { + // Handle new/existing group + const auto createResponse = + createNewGroup(groupName.isEmpty() ? PASSKEYS_DEFAULT_GROUP_NAME : groupName, true); + const auto group = db->rootGroup()->findGroupByUuid(Tools::hexToUuid(createResponse["uuid"].toString())); + addPasskeyToGroup(db, - nullptr, + group, origin, rpId, rpName, @@ -690,9 +771,9 @@ QJsonObject BrowserService::showPasskeysAuthenticationPrompt(const QJsonObject& return getPasskeyError(ERROR_PASSKEYS_UNKNOWN_ERROR); } - const auto privateKeyPem = selectedEntry->attributes()->value(BrowserPasskeys::KPEX_PASSKEY_PRIVATE_KEY_PEM); + const auto privateKeyPem = selectedEntry->attributes()->value(EntryAttributes::KPEX_PASSKEY_PRIVATE_KEY_PEM); const auto credentialId = passkeyUtils()->getCredentialIdFromEntry(selectedEntry); - const auto userHandle = selectedEntry->attributes()->value(BrowserPasskeys::KPEX_PASSKEY_USER_HANDLE); + const auto userHandle = selectedEntry->attributes()->value(EntryAttributes::KPEX_PASSKEY_USER_HANDLE); auto publicKeyCredential = browserPasskeys()->buildGetPublicKeyCredential(assertionOptions, credentialId, userHandle, privateKeyPem); @@ -770,11 +851,11 @@ void BrowserService::addPasskeyToEntry(Entry* entry, entry->beginUpdate(); - entry->attributes()->set(BrowserPasskeys::KPEX_PASSKEY_USERNAME, username); - entry->attributes()->set(BrowserPasskeys::KPEX_PASSKEY_CREDENTIAL_ID, credentialId, true); - entry->attributes()->set(BrowserPasskeys::KPEX_PASSKEY_PRIVATE_KEY_PEM, privateKey, true); - entry->attributes()->set(BrowserPasskeys::KPEX_PASSKEY_RELYING_PARTY, rpId); - entry->attributes()->set(BrowserPasskeys::KPEX_PASSKEY_USER_HANDLE, userHandle, true); + entry->attributes()->set(EntryAttributes::KPEX_PASSKEY_USERNAME, username); + entry->attributes()->set(EntryAttributes::KPEX_PASSKEY_CREDENTIAL_ID, credentialId, true); + entry->attributes()->set(EntryAttributes::KPEX_PASSKEY_PRIVATE_KEY_PEM, privateKey, true); + entry->attributes()->set(EntryAttributes::KPEX_PASSKEY_RELYING_PARTY, rpId); + entry->attributes()->set(EntryAttributes::KPEX_PASSKEY_USER_HANDLE, userHandle, true); entry->addTag(tr("Passkey")); entry->endUpdate(); @@ -920,9 +1001,19 @@ bool BrowserService::deleteEntry(const QString& uuid) return true; } +void BrowserService::removePluginData(Entry* entry) const +{ + if (entry) { + entry->beginUpdate(); + entry->customData()->remove(BrowserService::KEEPASSXCBROWSER_NAME); + entry->endUpdate(); + } +} + QList BrowserService::searchEntries(const QSharedPointer& db, const QString& siteUrl, const QString& formUrl, + const QStringList& keys, bool passkey) { QList entries; @@ -937,6 +1028,12 @@ QList BrowserService::searchEntries(const QSharedPointer& db, continue; } + // If a key restriction is specified and not contained in the keys list then skip this group. + auto restrictKey = group->resolveCustomDataString(BrowserService::OPTION_RESTRICT_KEY); + if (!restrictKey.isEmpty() && !keys.contains(restrictKey)) { + continue; + } + const auto omitWwwSubdomain = group->resolveCustomDataTriState(BrowserService::OPTION_OMIT_WWW) == Group::Enable; @@ -953,7 +1050,7 @@ QList BrowserService::searchEntries(const QSharedPointer& db, #ifdef WITH_XC_BROWSER_PASSKEYS // With Passkeys, check for the Relying Party instead of URL - if (passkey && entry->attributes()->value(BrowserPasskeys::KPEX_PASSKEY_RELYING_PARTY) != siteUrl) { + if (passkey && entry->attributes()->value(EntryAttributes::KPEX_PASSKEY_RELYING_PARTY) != siteUrl) { continue; } #endif @@ -973,30 +1070,36 @@ QList BrowserService::searchEntries(const QString& siteUrl, const StringPairList& keyList, bool passkey) { - // Check if database is connected with KeePassXC-Browser + // Check if database is connected with KeePassXC-Browser. If so, return browser key (otherwise empty) auto databaseConnected = [&](const QSharedPointer& db) { for (const StringPair& keyPair : keyList) { - QString key = db->metadata()->customData()->value(CustomData::BrowserKeyPrefix + keyPair.first); + const auto key = db->metadata()->customData()->value( + CustomData::getKeyWithPrefix(CustomData::BrowserKeyPrefix, keyPair.first)); if (!key.isEmpty() && keyPair.second == key) { - return true; + return keyPair.first; } } - return false; + return QString(); }; // Get the list of databases to search QList> databases; + QStringList keys; if (browserSettings()->searchInAllDatabases()) { for (auto dbWidget : getMainWindow()->getOpenDatabases()) { auto db = dbWidget->database(); - if (db && databaseConnected(dbWidget->database())) { + auto key = databaseConnected(dbWidget->database()); + if (db && !key.isEmpty()) { databases << db; + keys << key; } } } else { const auto& db = getDatabase(); - if (databaseConnected(db)) { + auto key = databaseConnected(db); + if (!key.isEmpty()) { databases << db; + keys << key; } } @@ -1005,84 +1108,16 @@ QList BrowserService::searchEntries(const QString& siteUrl, QList entries; do { for (const auto& db : databases) { - entries << searchEntries(db, siteUrl, formUrl, passkey); + entries << searchEntries(db, siteUrl, formUrl, keys, passkey); } } while (entries.isEmpty() && removeFirstDomain(hostname)); return entries; } -void BrowserService::convertAttributesToCustomData(QSharedPointer db) +QString BrowserService::decodeCustomDataRestrictKey(const QString& key) { - if (!db) { - return; - } - - QList entries = db->rootGroup()->entriesRecursive(); - QProgressDialog progress(tr("Converting attributes to custom data…"), tr("Abort"), 0, entries.count()); - progress.setWindowModality(Qt::WindowModal); - - int counter = 0; - int keyCounter = 0; - for (auto* entry : entries) { - if (progress.wasCanceled()) { - return; - } - - if (moveSettingsToCustomData(entry, KEEPASSHTTP_NAME)) { - ++counter; - } - - if (moveSettingsToCustomData(entry, KEEPASSXCBROWSER_OLD_NAME)) { - ++counter; - } - - if (moveSettingsToCustomData(entry, KEEPASSXCBROWSER_NAME)) { - ++counter; - } - - if (entry->title() == KEEPASSHTTP_NAME || entry->title().contains(KEEPASSXCBROWSER_NAME, Qt::CaseInsensitive)) { - keyCounter += moveKeysToCustomData(entry, db); - db->recycleEntry(entry); - } - - progress.setValue(progress.value() + 1); - } - progress.reset(); - - if (counter > 0) { - MessageBox::information(nullptr, - tr("KeePassXC: Converted KeePassHTTP attributes"), - tr("Successfully converted attributes from %1 entry(s).\n" - "Moved %2 keys to custom data.", - "") - .arg(counter) - .arg(keyCounter), - MessageBox::Ok); - } else if (counter == 0 && keyCounter > 0) { - MessageBox::information(nullptr, - tr("KeePassXC: Converted KeePassHTTP attributes"), - tr("Successfully moved %n keys to custom data.", "", keyCounter), - MessageBox::Ok); - } else { - MessageBox::information(nullptr, - tr("KeePassXC: No entry with KeePassHTTP attributes found!"), - tr("The active database does not contain an entry with KeePassHTTP attributes."), - MessageBox::Ok); - } - - // Rename password groupName - Group* rootGroup = db->rootGroup(); - if (!rootGroup) { - return; - } - - for (auto* g : rootGroup->groupsRecursive(true)) { - if (g->name() == KEEPASSHTTP_GROUP_NAME) { - g->setName(KEEPASSXCBROWSER_GROUP_NAME); - break; - } - } + return key.isEmpty() ? tr("Disable") : key; } void BrowserService::requestGlobalAutoType(const QString& search) @@ -1151,19 +1186,13 @@ void BrowserService::denyEntry(Entry* entry, const QString& siteHost, const QStr QJsonObject BrowserService::prepareEntry(const Entry* entry) { QJsonObject res; -#ifdef WITH_XC_BROWSER_PASSKEYS - // Use Passkey's username instead if found - res["login"] = entry->hasPasskey() ? passkeyUtils()->getUsernameFromEntry(entry) - : entry->resolveMultiplePlaceholders(entry->username()); -#else res["login"] = entry->resolveMultiplePlaceholders(entry->username()); -#endif res["password"] = entry->resolveMultiplePlaceholders(entry->password()); res["name"] = entry->resolveMultiplePlaceholders(entry->title()); res["uuid"] = entry->resolveMultiplePlaceholders(entry->uuidToHex()); res["group"] = entry->resolveMultiplePlaceholders(entry->group()->name()); - if (entry->hasTotp()) { + if (entry->hasValidTotp()) { res["totp"] = entry->totp(); } @@ -1348,9 +1377,15 @@ bool BrowserService::shouldIncludeEntry(Entry* entry, return url.endsWith("by-path/" + entry->path()); } - const auto allEntryUrls = entry->getAllUrls(); - for (const auto& entryUrl : allEntryUrls) { - if (handleURL(entryUrl, url, submitUrl, omitWwwSubdomain)) { + // Handle the entry URL + if (handleURL(entry->resolveUrl(), url, submitUrl, omitWwwSubdomain)) { + return true; + } + + // Handle additional URLs + const auto additionalUrls = entry->getAdditionalUrls(); + for (const auto& additionalUrl : additionalUrls) { + if (handleURL(additionalUrl, url, submitUrl, omitWwwSubdomain, true)) { return true; } } @@ -1364,7 +1399,7 @@ QList BrowserService::getPasskeyEntries(const QString& rpId, const Strin { QList entries; for (const auto& entry : searchEntries(rpId, "", keyList, true)) { - if (entry->hasPasskey() && entry->attributes()->value(BrowserPasskeys::KPEX_PASSKEY_RELYING_PARTY) == rpId) { + if (entry->hasPasskey() && entry->attributes()->value(EntryAttributes::KPEX_PASSKEY_RELYING_PARTY) == rpId) { entries << entry; } } @@ -1379,8 +1414,8 @@ QList BrowserService::getPasskeyEntriesWithUserHandle(const QString& rpI { QList entries; for (const auto& entry : searchEntries(rpId, "", keyList, true)) { - if (entry->hasPasskey() && entry->attributes()->value(BrowserPasskeys::KPEX_PASSKEY_RELYING_PARTY) == rpId - && entry->attributes()->value(BrowserPasskeys::KPEX_PASSKEY_USER_HANDLE) == userId) { + if (entry->hasPasskey() && entry->attributes()->value(EntryAttributes::KPEX_PASSKEY_RELYING_PARTY) == rpId + && entry->attributes()->value(EntryAttributes::KPEX_PASSKEY_USER_HANDLE) == userId) { entries << entry; } } @@ -1405,7 +1440,7 @@ QList BrowserService::getPasskeyAllowedEntries(const QJsonObject& assert // See: https://w3c.github.io/webauthn/#dom-authenticatorassertionresponse-userhandle if (allowedCredentials.contains(passkeyUtils()->getCredentialIdFromEntry(entry)) || (allowedCredentials.isEmpty() - && entry->attributes()->hasKey(BrowserPasskeys::KPEX_PASSKEY_USER_HANDLE))) { + && entry->attributes()->hasKey(EntryAttributes::KPEX_PASSKEY_USER_HANDLE))) { entries << entry; } } @@ -1438,17 +1473,35 @@ QJsonObject BrowserService::getPasskeyError(int errorCode) const bool BrowserService::handleURL(const QString& entryUrl, const QString& siteUrl, const QString& formUrl, - const bool omitWwwSubdomain) + const bool omitWwwSubdomain, + const bool allowWildcards) { if (entryUrl.isEmpty()) { return false; } + bool isWildcardUrl = false; + auto tempUrl = entryUrl; + + // Allows matching with exact URL and wildcards + if (allowWildcards) { + // Exact match where URL is wrapped inside " characters + if (entryUrl.startsWith("\"") && entryUrl.endsWith("\"")) { + return QStringView{entryUrl}.mid(1, entryUrl.length() - 2) == siteUrl; + } + + // Replace wildcards + isWildcardUrl = entryUrl.contains("*"); + if (isWildcardUrl) { + tempUrl = tempUrl.replace("*", UrlTools::URL_WILDCARD); + } + } + QUrl entryQUrl; if (entryUrl.contains("://")) { - entryQUrl = entryUrl; + entryQUrl = tempUrl; } else { - entryQUrl = QUrl::fromUserInput(entryUrl); + entryQUrl = QUrl::fromUserInput(tempUrl); if (browserSettings()->matchUrlScheme()) { entryQUrl.setScheme("https"); @@ -1488,6 +1541,11 @@ bool BrowserService::handleURL(const QString& entryUrl, return false; } + // Use wildcard matching instead + if (isWildcardUrl) { + return handleURLWithWildcards(entryQUrl, siteUrl); + } + // Match the base domain if (urlTools()->getBaseDomainFromUrl(siteQUrl.host()) != urlTools()->getBaseDomainFromUrl(entryQUrl.host())) { return false; @@ -1501,6 +1559,46 @@ bool BrowserService::handleURL(const QString& entryUrl, return false; } +bool BrowserService::handleURLWithWildcards(const QUrl& entryQUrl, const QString& siteUrl) +{ + auto matchWithRegex = [&](QString firstPart, const QString& secondPart, bool hostnameUsed = false) { + if (firstPart == secondPart) { + return true; + } + + // If there's no wildcard with hostname, just compare directly + if (hostnameUsed && !firstPart.contains(UrlTools::URL_WILDCARD) && firstPart != secondPart) { + return false; + } + + // Escape illegal characters + auto re = Tools::escapeRegex(firstPart); + + if (hostnameUsed) { + // Replace all host parts with wildcards + re = re.replace(QString("%1.").arg(UrlTools::URL_WILDCARD), "(.*?)\\."); + } + + // Append a + to the end of regex to match all paths after the last asterisk + if (re.endsWith(UrlTools::URL_WILDCARD)) { + re.append("+"); + } + + // Replace any remaining wildcards for paths + re = re.replace(UrlTools::URL_WILDCARD, "(.*?)"); + return QRegularExpression(re).match(secondPart).hasMatch(); + }; + + // Match hostname and path + QUrl siteQUrl = siteUrl; + if (!matchWithRegex(entryQUrl.host(), siteQUrl.host(), true) + || !matchWithRegex(entryQUrl.path(), siteQUrl.path())) { + return false; + } + + return true; +} + QSharedPointer BrowserService::getDatabase(const QUuid& rootGroupUuid) { if (!rootGroupUuid.isNull()) { @@ -1558,84 +1656,6 @@ QSharedPointer BrowserService::selectedDatabase() return getDatabase(); } -bool BrowserService::moveSettingsToCustomData(Entry* entry, const QString& name) -{ - if (entry->attributes()->contains(name)) { - QString attr = entry->attributes()->value(name); - entry->beginUpdate(); - if (!attr.isEmpty()) { - entry->customData()->set(KEEPASSXCBROWSER_NAME, attr); - } - entry->attributes()->remove(name); - entry->endUpdate(); - return true; - } - return false; -} - -int BrowserService::moveKeysToCustomData(Entry* entry, QSharedPointer db) -{ - int keyCounter = 0; - for (const auto& key : entry->attributes()->keys()) { - if (key.contains(CustomData::BrowserLegacyKeyPrefix)) { - QString publicKey = key; - publicKey.remove(CustomData::BrowserLegacyKeyPrefix); - - // Add key to database custom data - if (db && !db->metadata()->customData()->contains(CustomData::BrowserKeyPrefix + publicKey)) { - db->metadata()->customData()->set(CustomData::BrowserKeyPrefix + publicKey, - entry->attributes()->value(key)); - ++keyCounter; - } - } - } - - return keyCounter; -} - -bool BrowserService::checkLegacySettings(QSharedPointer db) -{ - if (!db || !browserSettings()->isEnabled() || browserSettings()->noMigrationPrompt()) { - return false; - } - - bool legacySettingsFound = false; - QList entries = db->rootGroup()->entriesRecursive(); - for (const auto& e : entries) { - if (e->isRecycled()) { - continue; - } - - if ((e->attributes()->contains(KEEPASSHTTP_NAME) || e->attributes()->contains(KEEPASSXCBROWSER_NAME)) - || (e->title() == KEEPASSHTTP_NAME || e->title().contains(KEEPASSXCBROWSER_NAME, Qt::CaseInsensitive))) { - legacySettingsFound = true; - break; - } - } - - if (!legacySettingsFound) { - return false; - } - - auto* checkbox = new QCheckBox(tr("Don't show this warning again")); - QObject::connect(checkbox, &QCheckBox::stateChanged, [&](int state) { - browserSettings()->setNoMigrationPrompt(static_cast(state) == Qt::CheckState::Checked); - }); - - auto dialogResult = - MessageBox::warning(nullptr, - tr("KeePassXC: Legacy browser integration settings detected"), - tr("Your KeePassXC-Browser settings need to be moved into the database settings.\n" - "This is necessary to maintain your current browser connections.\n" - "Would you like to migrate your existing settings now?"), - MessageBox::Yes | MessageBox::No, - MessageBox::NoButton, - MessageBox::Raise, - checkbox); - - return dialogResult == MessageBox::Yes; -} - void BrowserService::hideWindow() const { if (m_prevWindowState == WindowState::Minimized) { @@ -1719,11 +1739,6 @@ void BrowserService::databaseUnlocked(DatabaseWidget* dbWidget) QJsonObject msg; msg["action"] = QString("database-unlocked"); m_browserHost->broadcastClientMessage(msg); - - auto db = dbWidget->database(); - if (checkLegacySettings(db)) { - convertAttributesToCustomData(db); - } } } @@ -1740,6 +1755,15 @@ void BrowserService::activeDatabaseChanged(DatabaseWidget* dbWidget) m_currentDatabaseWidget = dbWidget; } +void BrowserService::handleDatabaseUnlockDialogFinished(bool accepted, DatabaseWidget* dbWidget) +{ + // User canceled the database open dialog + if (dbWidget && !accepted && m_bringToFrontRequested) { + m_bringToFrontRequested = false; + hideWindow(); + } +} + void BrowserService::processClientMessage(QLocalSocket* socket, const QJsonObject& message) { auto clientID = message["clientID"].toString(); diff --git a/src/browser/BrowserService.h b/src/browser/BrowserService.h index 46bebd38b..c59f9303d 100644 --- a/src/browser/BrowserService.h +++ b/src/browser/BrowserService.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2024 KeePassXC Team + * Copyright (C) 2025 KeePassXC Team * Copyright (C) 2017 Sami Vänttinen * Copyright (C) 2013 Francois Ferrand * @@ -79,7 +79,8 @@ public: void lockDatabase(); QJsonObject getDatabaseGroups(); - QJsonObject createNewGroup(const QString& groupName); + QJsonArray getDatabaseEntries(); + QJsonObject createNewGroup(const QString& groupName, bool isPasskeysGroup = false); QString getCurrentTotp(const QString& uuid); void showPasswordGenerator(const KeyPairMessage& keyPairMessage); bool isPasswordGeneratorRequested() const; @@ -89,6 +90,7 @@ public: #ifdef WITH_XC_BROWSER_PASSKEYS QJsonObject showPasskeysRegisterPrompt(const QJsonObject& publicKeyOptions, const QString& origin, + const QString& groupName, const StringPairList& keyList); QJsonObject showPasskeysAuthenticationPrompt(const QJsonObject& publicKeyOptions, const QString& origin, @@ -117,9 +119,11 @@ public: const QSharedPointer& selectedDb = {}); bool updateEntry(const EntryParameters& entryParameters, const QString& uuid); bool deleteEntry(const QString& uuid); + void removePluginData(Entry* entry) const; QJsonArray findEntries(const EntryParameters& entryParameters, const StringPairList& keyList, bool* entriesFound); void requestGlobalAutoType(const QString& search); - static void convertAttributesToCustomData(QSharedPointer db); + + static QString decodeCustomDataRestrictKey(const QString& key); static const QString KEEPASSXCBROWSER_NAME; static const QString KEEPASSXCBROWSER_OLD_NAME; @@ -128,6 +132,8 @@ public: static const QString OPTION_ONLY_HTTP_AUTH; static const QString OPTION_NOT_HTTP_AUTH; static const QString OPTION_OMIT_WWW; + static const QString ADDITIONAL_URL; + static const QString OPTION_RESTRICT_KEY; signals: void requestUnlock(); @@ -140,6 +146,7 @@ public slots: private slots: void processClientMessage(QLocalSocket* socket, const QJsonObject& message); + void handleDatabaseUnlockDialogFinished(bool accepted, DatabaseWidget* dbWidget); private: enum Access @@ -159,6 +166,7 @@ private: QList searchEntries(const QSharedPointer& db, const QString& siteUrl, const QString& formUrl, + const QStringList& keys = {}, bool passkey = false); QList searchEntries(const QString& siteUrl, const QString& formUrl, const StringPairList& keyList, bool passkey = false); @@ -192,18 +200,15 @@ private: bool handleURL(const QString& entryUrl, const QString& siteUrl, const QString& formUrl, - const bool omitWwwSubdomain = false); + const bool omitWwwSubdomain = false, + const bool allowWildcards = false); + bool handleURLWithWildcards(const QUrl& entryQUrl, const QString& siteUrl); QString getDatabaseRootUuid(); QString getDatabaseRecycleBinUuid(); - bool checkLegacySettings(QSharedPointer db); void hideWindow() const; void raiseWindow(const bool force = false); - void updateWindowState(); - static bool moveSettingsToCustomData(Entry* entry, const QString& name); - static int moveKeysToCustomData(Entry* entry, QSharedPointer db); - QPointer m_browserHost; QHash> m_browserClients; diff --git a/src/browser/BrowserSettings.cpp b/src/browser/BrowserSettings.cpp index 682a1a8ea..0a8226c12 100644 --- a/src/browser/BrowserSettings.cpp +++ b/src/browser/BrowserSettings.cpp @@ -237,6 +237,16 @@ void BrowserSettings::setUpdateBinaryPath(bool enabled) config()->set(Config::Browser_UpdateBinaryPath, enabled); } +bool BrowserSettings::allowGetDatabaseEntriesRequest() +{ + return config()->get(Config::Browser_AllowGetDatabaseEntriesRequest).toBool(); +} + +void BrowserSettings::setAllowGetDatabaseEntriesRequest(bool enabled) +{ + config()->set(Config::Browser_AllowGetDatabaseEntriesRequest, enabled); +} + bool BrowserSettings::allowExpiredCredentials() { return config()->get(Config::Browser_AllowExpiredCredentials).toBool(); diff --git a/src/browser/BrowserSettings.h b/src/browser/BrowserSettings.h index a0aaed8d5..9c0b3718e 100644 --- a/src/browser/BrowserSettings.h +++ b/src/browser/BrowserSettings.h @@ -66,6 +66,8 @@ public: #endif bool updateBinaryPath(); void setUpdateBinaryPath(bool enabled); + bool allowGetDatabaseEntriesRequest(); + void setAllowGetDatabaseEntriesRequest(bool enabled); bool allowExpiredCredentials(); void setAllowExpiredCredentials(bool enabled); diff --git a/src/browser/BrowserSettingsWidget.cpp b/src/browser/BrowserSettingsWidget.cpp index 36b7bdd4b..5a4ccce8d 100644 --- a/src/browser/BrowserSettingsWidget.cpp +++ b/src/browser/BrowserSettingsWidget.cpp @@ -31,23 +31,13 @@ BrowserSettingsWidget::BrowserSettingsWidget(QWidget* parent) m_ui->setupUi(this); // clang-format off - QString snapInstructions; -#if defined(KEEPASSXC_DIST_SNAP) - snapInstructions = "

    " + - tr("Due to Snap sandboxing, you must run a script to enable browser integration." - "
    " - "You can obtain this script from %1") - .arg("https://keepassxc.org"); -#endif - m_ui->extensionLabel->setOpenExternalLinks(true); m_ui->extensionLabel->setText( - tr("KeePassXC-Browser is needed for the browser integration to work.
    Download it for %1 and %2 and %3. %4") + tr("KeePassXC-Browser is needed for the browser integration to work.
    Download it for %1 and %2 and %3.") .arg("Firefox", - "" + "" "Google Chrome / Chromium / Vivaldi / Brave", - "Microsoft Edge", - snapInstructions)); + "Microsoft Edge")); // clang-format on m_ui->tabWidget->setEnabled(m_ui->enableBrowserSupport->isChecked()); @@ -128,6 +118,7 @@ void BrowserSettingsWidget::loadSettings() m_ui->useCustomProxy->setChecked(settings->useCustomProxy()); m_ui->customProxyLocation->setText(settings->replaceHomePath(settings->customProxyLocation())); m_ui->updateBinaryPath->setChecked(settings->updateBinaryPath()); + m_ui->allowGetDatabaseEntriesRequest->setChecked(settings->allowGetDatabaseEntriesRequest()); m_ui->allowExpiredCredentials->setChecked(settings->allowExpiredCredentials()); m_ui->chromeSupport->setChecked(settings->browserSupport(BrowserShared::CHROME)); m_ui->chromiumSupport->setChecked(settings->browserSupport(BrowserShared::CHROMIUM)); @@ -148,16 +139,11 @@ void BrowserSettingsWidget::loadSettings() m_ui->useCustomProxy->setVisible(false); m_ui->customProxyLocation->setVisible(false); m_ui->customProxyLocationBrowseButton->setVisible(false); - m_ui->browsersGroupBox->setVisible(false); - m_ui->browsersGroupBox->setEnabled(false); m_ui->updateBinaryPath->setChecked(false); m_ui->updateBinaryPath->setVisible(false); // No custom browser for snaps m_ui->customBrowserSupport->setVisible(false); m_ui->customBrowserGroupBox->setVisible(false); - // Show notice to user - m_ui->messageWidget->showMessage(tr("Please see special instructions for browser extension use below"), - MessageWidget::Warning); #endif #ifdef KEEPASSXC_DIST_FLATPAK // The sandbox makes custom proxy locations very unintuitive @@ -192,7 +178,7 @@ void BrowserSettingsWidget::loadSettings() QString BrowserSettingsWidget::resolveCustomProxyLocation() { auto settings = browserSettings(); - auto proxyLocation = m_ui->customProxyLocation->text(); + auto proxyLocation = m_ui->customProxyLocation->text().trimmed(); proxyLocation = settings->replaceTildeHomePath(proxyLocation); return proxyLocation; } @@ -246,6 +232,7 @@ void BrowserSettingsWidget::saveSettings() settings->setCustomProxyLocation(resolveCustomProxyLocation()); settings->setUpdateBinaryPath(m_ui->updateBinaryPath->isChecked()); + settings->setAllowGetDatabaseEntriesRequest(m_ui->allowGetDatabaseEntriesRequest->isChecked()); settings->setAllowExpiredCredentials(m_ui->allowExpiredCredentials->isChecked()); settings->setAlwaysAllowAccess(m_ui->alwaysAllowAccess->isChecked()); settings->setAlwaysAllowUpdate(m_ui->alwaysAllowUpdate->isChecked()); diff --git a/src/browser/BrowserSettingsWidget.ui b/src/browser/BrowserSettingsWidget.ui index 3444b219a..99db4ede6 100644 --- a/src/browser/BrowserSettingsWidget.ui +++ b/src/browser/BrowserSettingsWidget.ui @@ -52,7 +52,7 @@ - Browsers installed as snaps are currently not supported. + Browsers installed using Snap or Flatpak are not supported with exception to Firefox installed using Snap. @@ -340,6 +340,16 @@ + + + + Allow keepassxc-proxy to list all entries with their title, URL and UUID in connected databases. + + + Allow limited access to all entries in connected databases (ignores site access restrictions) + + + @@ -487,7 +497,7 @@ - + diff --git a/src/browser/CMakeLists.txt b/src/browser/CMakeLists.txt old mode 100755 new mode 100644 index 2c344d31b..7942be430 --- a/src/browser/CMakeLists.txt +++ b/src/browser/CMakeLists.txt @@ -16,7 +16,7 @@ if(WITH_XC_BROWSER) include_directories(${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR}) - set(keepassxcbrowser_SOURCES + set(browser_SOURCES BrowserAccessControlDialog.cpp BrowserAction.cpp BrowserEntryConfig.cpp @@ -28,10 +28,11 @@ if(WITH_XC_BROWSER) BrowserService.cpp BrowserSettings.cpp BrowserShared.cpp + CustomTableWidget.cpp NativeMessageInstaller.cpp) if(WITH_XC_BROWSER_PASSKEYS) - list(APPEND keepassxcbrowser_SOURCES + list(APPEND browser_SOURCES BrowserCbor.cpp BrowserPasskeys.cpp BrowserPasskeysClient.cpp @@ -39,6 +40,6 @@ if(WITH_XC_BROWSER) PasskeyUtils.cpp) endif() - add_library(keepassxcbrowser STATIC ${keepassxcbrowser_SOURCES}) - target_link_libraries(keepassxcbrowser Qt5::Core Qt5::Concurrent Qt5::Widgets Qt5::Network ${BOTAN_LIBRARIES}) + add_library(browser STATIC ${browser_SOURCES}) + target_link_libraries(browser Qt5::Core Qt5::Concurrent Qt5::Widgets Qt5::Network ${BOTAN_LIBRARIES}) endif() diff --git a/src/browser/CustomTableWidget.cpp b/src/browser/CustomTableWidget.cpp new file mode 100644 index 000000000..29009f4d5 --- /dev/null +++ b/src/browser/CustomTableWidget.cpp @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2023 KeePassXC Team + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "CustomTableWidget.h" + +CustomTableWidget::CustomTableWidget(QWidget* parent) + : QTableWidget(parent) +{ +} + +void CustomTableWidget::keyPressEvent(QKeyEvent* event) +{ + if ((event->key() == Qt::Key_Enter || event->key() == Qt::Key_Return) && !selectedItems().isEmpty()) { + emit acceptSelections(); + } else { + QTableView::keyPressEvent(event); + } +} + +void CustomTableWidget::focusInEvent(QFocusEvent* event) +{ + // For some reason accept button gets selected if table is clicked without any + // selections, even if the button is actually disabled. Connecting to this + // signal and adjusting the button focuses fixes the issue. + if (event->reason() == Qt::MouseFocusReason && selectedItems().isEmpty()) { + emit focusInWithoutSelections(); + } +} diff --git a/src/browser/CustomTableWidget.h b/src/browser/CustomTableWidget.h new file mode 100644 index 000000000..655475e9d --- /dev/null +++ b/src/browser/CustomTableWidget.h @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2023 KeePassXC Team + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef CUSTOMTABLEWIDGET_H +#define CUSTOMTABLEWIDGET_H + +#include +#include +#include + +class CustomTableWidget : public QTableWidget +{ + Q_OBJECT + +public: + CustomTableWidget(QWidget* parent); + +signals: + void acceptSelections(); + void focusInWithoutSelections(); + +protected: + void keyPressEvent(QKeyEvent* event) override; + void focusInEvent(QFocusEvent* event) override; +}; + +#endif // CUSTOMTABLEWIDGET_H diff --git a/src/browser/NativeMessageInstaller.cpp b/src/browser/NativeMessageInstaller.cpp index 7409989ab..b8beba7ad 100644 --- a/src/browser/NativeMessageInstaller.cpp +++ b/src/browser/NativeMessageInstaller.cpp @@ -1,6 +1,5 @@ /* - * Copyright (C) 2017 Sami Vänttinen - * Copyright (C) 2021 KeePassXC Team + * Copyright (C) 2025 KeePassXC Team * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -19,6 +18,7 @@ #include "NativeMessageInstaller.h" #include "BrowserSettings.h" #include "config-keepassx.h" +#include "core/Config.h" #include #include @@ -69,7 +69,7 @@ namespace const QString TARGET_DIR_FIREFOX = QStringLiteral("/.mozilla/native-messaging-hosts"); const QString TARGET_DIR_VIVALDI = QStringLiteral("/vivaldi/NativeMessagingHosts"); const QString TARGET_DIR_TOR_BROWSER = QStringLiteral( - "/torbrowser/tbb/x86_64/tor-browser_en-US/Browser/TorBrowser/Data/Browser/.mozilla/native-messaging-hosts"); + "/torbrowser/tbb/x86_64/tor-browser/Browser/TorBrowser/Data/Browser/.mozilla/native-messaging-hosts"); const QString TARGET_DIR_BRAVE = QStringLiteral("/BraveSoftware/Brave-Browser/NativeMessagingHosts"); const QString TARGET_DIR_EDGE = QStringLiteral("/microsoft-edge/NativeMessagingHosts"); #endif @@ -209,8 +209,8 @@ QString NativeMessageInstaller::getNativeMessagePath(SupportedBrowsers browser) QString basePath; #if defined(Q_OS_WIN) // If portable settings file exists save the JSON scripts to the application folder - if (QFile::exists(QCoreApplication::applicationDirPath() + QStringLiteral("/keepassxc.ini"))) { - basePath = QCoreApplication::applicationDirPath(); + if (Config::isPortable()) { + basePath = Config::portableConfigDir(); } else { basePath = QStandardPaths::writableLocation(QStandardPaths::DataLocation); } @@ -225,6 +225,16 @@ QString NativeMessageInstaller::getNativeMessagePath(SupportedBrowsers browser) } else { basePath = QDir::homePath() + "/.config"; } +#elif defined(KEEPASSXC_DIST_SNAP) + // Same as Flatpak above, with the exception that Snap also redefines $HOME + // Therefore we must explicitly reference $SNAP_REAL_HOME + if (browser == SupportedBrowsers::TOR_BROWSER) { + basePath = qEnvironmentVariable("SNAP_REAL_HOME") + "/.local/share"; + } else if (browser == SupportedBrowsers::FIREFOX) { + basePath = qEnvironmentVariable("SNAP_REAL_HOME"); + } else { + basePath = qEnvironmentVariable("SNAP_REAL_HOME") + "/.config"; + } #elif defined(Q_OS_LINUX) || (defined(Q_OS_UNIX) && !defined(Q_OS_MACOS)) if (browser == SupportedBrowsers::TOR_BROWSER) { basePath = QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation); @@ -295,6 +305,8 @@ QString NativeMessageInstaller::getInstalledProxyPath() const path = QProcessEnvironment::systemEnvironment().value("APPIMAGE"); #elif defined(KEEPASSXC_DIST_FLATPAK) path = constructFlatpakPath(); +#elif defined(KEEPASSXC_DIST_SNAP) + path = "/snap/bin/keepassxc.proxy"; #else path = QCoreApplication::applicationDirPath() + QStringLiteral("/keepassxc-proxy"); #ifdef Q_OS_WIN diff --git a/src/browser/PasskeyUtils.cpp b/src/browser/PasskeyUtils.cpp index fac9af09b..b28c94dbb 100644 --- a/src/browser/PasskeyUtils.cpp +++ b/src/browser/PasskeyUtils.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2024 KeePassXC Team + * Copyright (C) 2025 KeePassXC Team * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -18,8 +18,9 @@ #include "PasskeyUtils.h" #include "BrowserMessageBuilder.h" #include "BrowserPasskeys.h" +#include "core/EntryAttributes.h" #include "core/Tools.h" -#include "core/UrlTools.h" +#include "gui/UrlTools.h" #include #include @@ -52,8 +53,8 @@ bool PasskeyUtils::checkCredentialCreationOptions(const QJsonObject& credentialC { if (!credentialCreationOptions["attestation"].isString() || credentialCreationOptions["attestation"].toString().isEmpty() - || !credentialCreationOptions["clientDataJSON"].isObject() - || credentialCreationOptions["clientDataJSON"].toObject().isEmpty() + || !credentialCreationOptions["clientDataJSON"].isString() + || credentialCreationOptions["clientDataJSON"].toString().isEmpty() || !credentialCreationOptions["rp"].isObject() || credentialCreationOptions["rp"].toObject().isEmpty() || !credentialCreationOptions["user"].isObject() || credentialCreationOptions["user"].toObject().isEmpty() || !credentialCreationOptions["residentKey"].isBool() || credentialCreationOptions["residentKey"].isUndefined() @@ -74,7 +75,7 @@ bool PasskeyUtils::checkCredentialCreationOptions(const QJsonObject& credentialC // Basic check for the object that it contains necessary variables in a correct form bool PasskeyUtils::checkCredentialAssertionOptions(const QJsonObject& assertionOptions) const { - if (!assertionOptions["clientDataJson"].isObject() || assertionOptions["clientDataJson"].toObject().isEmpty() + if (!assertionOptions["clientDataJson"].isString() || assertionOptions["clientDataJson"].toString().isEmpty() || !assertionOptions["rpId"].isString() || assertionOptions["rpId"].toString().isEmpty() || !assertionOptions["userPresence"].isBool() || assertionOptions["userPresence"].isUndefined() || !assertionOptions["userVerification"].isBool() || assertionOptions["userVerification"].isUndefined()) { @@ -351,15 +352,11 @@ ExtensionResult PasskeyUtils::buildExtensionData(QJsonObject& extensionObject) c return {}; } -QJsonObject PasskeyUtils::buildClientDataJson(const QJsonObject& publicKey, const QString& origin, bool get) const +// Serialization order: https://w3c.github.io/webauthn/#clientdatajson-serialization +QString PasskeyUtils::buildClientDataJson(const QJsonObject& publicKey, const QString& origin, bool get) const { - QJsonObject clientData; - clientData["challenge"] = publicKey["challenge"]; - clientData["crossOrigin"] = false; - clientData["origin"] = origin; - clientData["type"] = get ? QString("webauthn.get") : QString("webauthn.create"); - - return clientData; + return QString("{\"type\":\"%1\",\"challenge\":\"%2\",\"origin\":\"%3\",\"crossOrigin\":false}") + .arg((get ? QString("webauthn.get") : QString("webauthn.create")), publicKey["challenge"].toString(), origin); } QStringList PasskeyUtils::getAllowedCredentialsFromAssertionOptions(const QJsonObject& assertionOptions) const @@ -389,9 +386,9 @@ QString PasskeyUtils::getCredentialIdFromEntry(const Entry* entry) const return {}; } - return entry->attributes()->hasKey(BrowserPasskeys::KPEX_PASSKEY_GENERATED_USER_ID) - ? entry->attributes()->value(BrowserPasskeys::KPEX_PASSKEY_GENERATED_USER_ID) - : entry->attributes()->value(BrowserPasskeys::KPEX_PASSKEY_CREDENTIAL_ID); + return entry->attributes()->hasKey(EntryAttributes::KPEX_PASSKEY_GENERATED_USER_ID) + ? entry->attributes()->value(EntryAttributes::KPEX_PASSKEY_GENERATED_USER_ID) + : entry->attributes()->value(EntryAttributes::KPEX_PASSKEY_CREDENTIAL_ID); } // For compatibility with StrongBox (and other possible clients in the future) @@ -401,7 +398,7 @@ QString PasskeyUtils::getUsernameFromEntry(const Entry* entry) const return {}; } - return entry->attributes()->hasKey(BrowserPasskeys::KPXC_PASSKEY_USERNAME) - ? entry->attributes()->value(BrowserPasskeys::KPXC_PASSKEY_USERNAME) - : entry->attributes()->value(BrowserPasskeys::KPEX_PASSKEY_USERNAME); + return entry->attributes()->hasKey(EntryAttributes::KPXC_PASSKEY_USERNAME) + ? entry->attributes()->value(EntryAttributes::KPXC_PASSKEY_USERNAME) + : entry->attributes()->value(EntryAttributes::KPEX_PASSKEY_USERNAME); } diff --git a/src/browser/PasskeyUtils.h b/src/browser/PasskeyUtils.h index ec8e47668..b1e6a48ab 100644 --- a/src/browser/PasskeyUtils.h +++ b/src/browser/PasskeyUtils.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2024 KeePassXC Team + * Copyright (C) 2025 KeePassXC Team * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -58,7 +58,7 @@ public: bool isUserVerificationRequired(const QJsonObject& authenticatorSelection) const; bool isOriginAllowedWithLocalhost(bool allowLocalhostWithPasskeys, const QString& origin) const; ExtensionResult buildExtensionData(QJsonObject& extensionObject) const; - QJsonObject buildClientDataJson(const QJsonObject& publicKey, const QString& origin, bool get) const; + QString buildClientDataJson(const QJsonObject& publicKey, const QString& origin, bool get) const; QStringList getAllowedCredentialsFromAssertionOptions(const QJsonObject& assertionOptions) const; QString getCredentialIdFromEntry(const Entry* entry) const; QString getUsernameFromEntry(const Entry* entry) const; diff --git a/src/cli/Add.cpp b/src/cli/Add.cpp index 3bd9241d1..43710b7a4 100644 --- a/src/cli/Add.cpp +++ b/src/cli/Add.cpp @@ -19,13 +19,13 @@ #include "Generate.h" #include "Utils.h" +#include "core/Global.h" #include "core/Group.h" #include "core/PasswordGenerator.h" #include -const QCommandLineOption Add::UsernameOption = QCommandLineOption(QStringList() << "u" - << "username", +const QCommandLineOption Add::UsernameOption = QCommandLineOption(QStringList() << "u" << "username", QObject::tr("Username for the entry."), QObject::tr("username")); @@ -36,13 +36,10 @@ const QCommandLineOption Add::NotesOption = QCommandLineOption(QStringList() << "notes", QObject::tr("Notes for the entry."), QObject::tr("Notes")); const QCommandLineOption Add::PasswordPromptOption = - QCommandLineOption(QStringList() << "p" - << "password-prompt", - QObject::tr("Prompt for the entry's password.")); + QCommandLineOption(QStringList() << "p" << "password-prompt", QObject::tr("Prompt for the entry's password.")); -const QCommandLineOption Add::GenerateOption = QCommandLineOption(QStringList() << "g" - << "generate", - QObject::tr("Generate a password for the entry.")); +const QCommandLineOption Add::GenerateOption = + QCommandLineOption(QStringList() << "g" << "generate", QObject::tr("Generate a password for the entry.")); Add::Add() { @@ -78,7 +75,7 @@ int Add::executeWithDatabase(QSharedPointer database, QSharedPointerisSet(Add::GenerateOption) && parser->isSet(Add::PasswordPromptOption)) { - err << QObject::tr("Cannot generate a password and prompt at the same time.") << endl; + err << QObject::tr("Cannot generate a password and prompt at the same time.") << Qt::endl; return EXIT_FAILURE; } @@ -94,7 +91,7 @@ int Add::executeWithDatabase(QSharedPointer database, QSharedPointerrootGroup()->addEntryWithPath(entryPath); if (!entry) { - err << QObject::tr("Could not create entry with path %1.").arg(entryPath) << endl; + err << QObject::tr("Could not create entry with path %1.").arg(entryPath) << Qt::endl; return EXIT_FAILURE; } @@ -112,7 +109,7 @@ int Add::executeWithDatabase(QSharedPointer database, QSharedPointerisSet(Add::PasswordPromptOption)) { if (!parser->isSet(Command::QuietOption)) { - out << QObject::tr("Enter password for new entry: ") << flush; + out << QObject::tr("Enter password for new entry: ") << Qt::flush; } QString password = Utils::getPassword(parser->isSet(Command::QuietOption)); entry->setPassword(password); @@ -123,12 +120,12 @@ int Add::executeWithDatabase(QSharedPointer database, QSharedPointersave(Database::Atomic, {}, &errorMessage)) { - err << QObject::tr("Writing the database failed %1.").arg(errorMessage) << endl; + err << QObject::tr("Writing the database failed %1.").arg(errorMessage) << Qt::endl; return EXIT_FAILURE; } if (!parser->isSet(Command::QuietOption)) { - out << QObject::tr("Successfully added entry %1.").arg(entry->title()) << endl; + out << QObject::tr("Successfully added entry %1.").arg(entry->title()) << Qt::endl; } return EXIT_SUCCESS; } diff --git a/src/cli/AddGroup.cpp b/src/cli/AddGroup.cpp index 43431e8dc..2e4bbeac1 100644 --- a/src/cli/AddGroup.cpp +++ b/src/cli/AddGroup.cpp @@ -18,6 +18,7 @@ #include "AddGroup.h" #include "Utils.h" +#include "core/Global.h" #include "core/Group.h" #include @@ -29,9 +30,7 @@ AddGroup::AddGroup() positionalArguments.append({QString("group"), QObject::tr("Path of the group to add."), QString("")}); } -AddGroup::~AddGroup() -{ -} +AddGroup::~AddGroup() = default; int AddGroup::executeWithDatabase(QSharedPointer database, QSharedPointer parser) { @@ -47,29 +46,29 @@ int AddGroup::executeWithDatabase(QSharedPointer database, QSharedPoin Group* group = database->rootGroup()->findGroupByPath(groupPath); if (group) { - err << QObject::tr("Group %1 already exists!").arg(groupPath) << endl; + err << QObject::tr("Group %1 already exists!").arg(groupPath) << Qt::endl; return EXIT_FAILURE; } Group* parentGroup = database->rootGroup()->findGroupByPath(parentGroupPath); if (!parentGroup) { - err << QObject::tr("Group %1 not found.").arg(parentGroupPath) << endl; + err << QObject::tr("Group %1 not found.").arg(parentGroupPath) << Qt::endl; return EXIT_FAILURE; } - Group* newGroup = new Group(); + auto newGroup = new Group(); newGroup->setUuid(QUuid::createUuid()); newGroup->setName(groupName); newGroup->setParent(parentGroup); QString errorMessage; if (!database->save(Database::Atomic, {}, &errorMessage)) { - err << QObject::tr("Writing the database failed %1.").arg(errorMessage) << endl; + err << QObject::tr("Writing the database failed %1.").arg(errorMessage) << Qt::endl; return EXIT_FAILURE; } if (!parser->isSet(Command::QuietOption)) { - out << QObject::tr("Successfully added group %1.").arg(groupName) << endl; + out << QObject::tr("Successfully added group %1.").arg(groupName) << Qt::endl; } return EXIT_SUCCESS; } diff --git a/src/cli/AddGroup.h b/src/cli/AddGroup.h index 9976d5894..7992f16bf 100644 --- a/src/cli/AddGroup.h +++ b/src/cli/AddGroup.h @@ -24,9 +24,9 @@ class AddGroup : public DatabaseCommand { public: AddGroup(); - ~AddGroup(); + ~AddGroup() override; - int executeWithDatabase(QSharedPointer db, QSharedPointer parser); + int executeWithDatabase(QSharedPointer db, QSharedPointer parser) override; }; #endif // KEEPASSXC_ADDGROUP_H diff --git a/src/cli/Analyze.cpp b/src/cli/Analyze.cpp index 185339dc5..44704014a 100644 --- a/src/cli/Analyze.cpp +++ b/src/cli/Analyze.cpp @@ -18,6 +18,7 @@ #include "Analyze.h" #include "Utils.h" +#include "core/Global.h" #include "core/Group.h" #include "core/HibpOffline.h" @@ -60,23 +61,24 @@ int Analyze::executeWithDatabase(QSharedPointer database, QSharedPoint auto okon = parser->value(Analyze::OkonOption); if (!okon.isEmpty()) { - out << QObject::tr("Evaluating database entries using okon…") << endl; + out << QObject::tr("Evaluating database entries using okon…") << Qt::endl; if (!HibpOffline::okonReport(database, okon, hibpDatabase, findings, &error)) { - err << error << endl; + err << error << Qt::endl; return EXIT_FAILURE; } } else { QFile hibpFile(hibpDatabase); if (!hibpFile.open(QFile::ReadOnly)) { - err << QObject::tr("Failed to open HIBP file %1: %2").arg(hibpDatabase).arg(hibpFile.errorString()) << endl; + err << QObject::tr("Failed to open HIBP file %1: %2").arg(hibpDatabase).arg(hibpFile.errorString()) + << Qt::endl; return EXIT_FAILURE; } - out << QObject::tr("Evaluating database entries against HIBP file, this will take a while…") << endl; + out << QObject::tr("Evaluating database entries against HIBP file, this will take a while…") << Qt::endl; if (!HibpOffline::report(database, hibpFile, findings, &error)) { - err << error << endl; + err << error << Qt::endl; return EXIT_FAILURE; } } @@ -91,9 +93,10 @@ int Analyze::executeWithDatabase(QSharedPointer database, QSharedPoint } if (count > 0) { - out << QObject::tr("Password for '%1' has been leaked %2 time(s)!", "", count).arg(path).arg(count) << endl; + out << QObject::tr("Password for '%1' has been leaked %2 time(s)!", "", count).arg(path).arg(count) + << Qt::endl; } else { - out << QObject::tr("Password for '%1' has been leaked!").arg(path) << endl; + out << QObject::tr("Password for '%1' has been leaked!").arg(path) << Qt::endl; } } diff --git a/src/cli/AttachmentExport.cpp b/src/cli/AttachmentExport.cpp index 46dc5f4b6..b4c88d902 100644 --- a/src/cli/AttachmentExport.cpp +++ b/src/cli/AttachmentExport.cpp @@ -18,6 +18,7 @@ #include "AttachmentExport.h" #include "Utils.h" +#include "core/Global.h" #include "core/Group.h" #include @@ -49,7 +50,7 @@ int AttachmentExport::executeWithDatabase(QSharedPointer database, QSh auto entry = database->rootGroup()->findEntryByPath(entryPath); if (!entry) { - err << QObject::tr("Could not find entry with path %1.").arg(entryPath) << endl; + err << QObject::tr("Could not find entry with path %1.").arg(entryPath) << Qt::endl; return EXIT_FAILURE; } @@ -57,32 +58,32 @@ int AttachmentExport::executeWithDatabase(QSharedPointer database, QSh auto attachments = entry->attachments(); if (!attachments->hasKey(attachmentName)) { - err << QObject::tr("Could not find attachment with name %1.").arg(attachmentName) << endl; + err << QObject::tr("Could not find attachment with name %1.").arg(attachmentName) << Qt::endl; return EXIT_FAILURE; } if (parser->isSet(AttachmentExport::StdoutOption)) { // Output to STDOUT even in quiet mode - Utils::STDOUT << attachments->value(attachmentName) << flush; + Utils::STDOUT << attachments->value(attachmentName) << Qt::flush; return EXIT_SUCCESS; } if (args.size() < 4) { - err << QObject::tr("No export target given. Please use '--stdout' or specify an 'export-file'.") << endl; + err << QObject::tr("No export target given. Please use '--stdout' or specify an 'export-file'.") << Qt::endl; return EXIT_FAILURE; } auto exportFileName = args.at(3); QFile exportFile(exportFileName); if (!exportFile.open(QIODevice::WriteOnly)) { - err << QObject::tr("Could not open output file %1.").arg(exportFileName) << endl; + err << QObject::tr("Could not open output file %1.").arg(exportFileName) << Qt::endl; return EXIT_FAILURE; } exportFile.write(attachments->value(attachmentName)); out << QObject::tr("Successfully exported attachment %1 of entry %2 to %3.") .arg(attachmentName, entryPath, exportFileName) - << endl; + << Qt::endl; return EXIT_SUCCESS; } diff --git a/src/cli/AttachmentImport.cpp b/src/cli/AttachmentImport.cpp index 0700961d7..6fe6ce529 100644 --- a/src/cli/AttachmentImport.cpp +++ b/src/cli/AttachmentImport.cpp @@ -18,15 +18,14 @@ #include "AttachmentImport.h" #include "Utils.h" +#include "core/Global.h" #include "core/Group.h" #include #include const QCommandLineOption AttachmentImport::ForceOption = - QCommandLineOption(QStringList() << "f" - << "force", - QObject::tr("Overwrite existing attachments.")); + QCommandLineOption(QStringList() << "f" << "force", QObject::tr("Overwrite existing attachments.")); AttachmentImport::AttachmentImport() { @@ -50,7 +49,7 @@ int AttachmentImport::executeWithDatabase(QSharedPointer database, QSh auto entry = database->rootGroup()->findEntryByPath(entryPath); if (!entry) { - err << QObject::tr("Could not find entry with path %1.").arg(entryPath) << endl; + err << QObject::tr("Could not find entry with path %1.").arg(entryPath) << Qt::endl; return EXIT_FAILURE; } @@ -58,7 +57,7 @@ int AttachmentImport::executeWithDatabase(QSharedPointer database, QSh auto attachments = entry->attachments(); if (attachments->hasKey(attachmentName) && !parser->isSet(AttachmentImport::ForceOption)) { - err << QObject::tr("Attachment %1 already exists for entry %2.").arg(attachmentName, entryPath) << endl; + err << QObject::tr("Attachment %1 already exists for entry %2.").arg(attachmentName, entryPath) << Qt::endl; return EXIT_FAILURE; } @@ -66,7 +65,7 @@ int AttachmentImport::executeWithDatabase(QSharedPointer database, QSh QFile importFile(importFileName); if (!importFile.open(QIODevice::ReadOnly)) { - err << QObject::tr("Could not open attachment file %1.").arg(importFileName) << endl; + err << QObject::tr("Could not open attachment file %1.").arg(importFileName) << Qt::endl; return EXIT_FAILURE; } @@ -76,12 +75,12 @@ int AttachmentImport::executeWithDatabase(QSharedPointer database, QSh QString errorMessage; if (!database->save(Database::Atomic, {}, &errorMessage)) { - err << QObject::tr("Writing the database failed %1.").arg(errorMessage) << endl; + err << QObject::tr("Writing the database failed %1.").arg(errorMessage) << Qt::endl; return EXIT_FAILURE; } out << QObject::tr("Successfully imported attachment %1 as %2 to entry %3.") .arg(importFileName, attachmentName, entryPath) - << endl; + << Qt::endl; return EXIT_SUCCESS; } diff --git a/src/cli/AttachmentRemove.cpp b/src/cli/AttachmentRemove.cpp index a609a8f22..c8ce4d46c 100644 --- a/src/cli/AttachmentRemove.cpp +++ b/src/cli/AttachmentRemove.cpp @@ -18,6 +18,7 @@ #include "AttachmentRemove.h" #include "Utils.h" +#include "core/Global.h" #include "core/Group.h" #include @@ -41,7 +42,7 @@ int AttachmentRemove::executeWithDatabase(QSharedPointer database, QSh auto entry = database->rootGroup()->findEntryByPath(entryPath); if (!entry) { - err << QObject::tr("Could not find entry with path %1.").arg(entryPath) << endl; + err << QObject::tr("Could not find entry with path %1.").arg(entryPath) << Qt::endl; return EXIT_FAILURE; } @@ -49,7 +50,7 @@ int AttachmentRemove::executeWithDatabase(QSharedPointer database, QSh auto attachments = entry->attachments(); if (!attachments->hasKey(attachmentName)) { - err << QObject::tr("Could not find attachment with name %1.").arg(attachmentName) << endl; + err << QObject::tr("Could not find attachment with name %1.").arg(attachmentName) << Qt::endl; return EXIT_FAILURE; } @@ -59,10 +60,10 @@ int AttachmentRemove::executeWithDatabase(QSharedPointer database, QSh QString errorMessage; if (!database->save(Database::Atomic, {}, &errorMessage)) { - err << QObject::tr("Writing the database failed %1.").arg(errorMessage) << endl; + err << QObject::tr("Writing the database failed %1.").arg(errorMessage) << Qt::endl; return EXIT_FAILURE; } - out << QObject::tr("Successfully removed attachment %1 from entry %2.").arg(attachmentName, entryPath) << endl; + out << QObject::tr("Successfully removed attachment %1 from entry %2.").arg(attachmentName, entryPath) << Qt::endl; return EXIT_SUCCESS; } diff --git a/src/cli/CMakeLists.txt b/src/cli/CMakeLists.txt index a3852c800..ecd5da284 100644 --- a/src/cli/CMakeLists.txt +++ b/src/cli/CMakeLists.txt @@ -45,7 +45,7 @@ set(cli_SOURCES Show.cpp) add_library(cli STATIC ${cli_SOURCES}) -target_link_libraries(cli Qt5::Core) +target_link_libraries(cli ${ZXCVBN_LIBRARIES} Qt5::Core) find_package(Readline) @@ -58,7 +58,7 @@ add_executable(keepassxc-cli keepassxc-cli.cpp) target_link_libraries(keepassxc-cli ${GPGERROR_LIBRARIES} cli - keepassx_core) + keepassxc_core) install(TARGETS keepassxc-cli BUNDLE DESTINATION . COMPONENT Runtime diff --git a/src/cli/Clip.cpp b/src/cli/Clip.cpp index 47964b190..364072fdd 100644 --- a/src/cli/Clip.cpp +++ b/src/cli/Clip.cpp @@ -27,21 +27,18 @@ #define CLI_DEFAULT_CLIP_TIMEOUT 10 const QCommandLineOption Clip::AttributeOption = QCommandLineOption( - QStringList() << "a" - << "attribute", + QStringList() << "a" << "attribute", QObject::tr("Copy the given attribute to the clipboard. Defaults to \"password\" if not specified.", "Don't translate \"password\", it refers to the attribute."), "attr", "password"); const QCommandLineOption Clip::TotpOption = - QCommandLineOption(QStringList() << "t" - << "totp", + QCommandLineOption(QStringList() << "t" << "totp", QObject::tr("Copy the current TOTP to the clipboard (equivalent to \"-a totp\").")); const QCommandLineOption Clip::BestMatchOption = - QCommandLineOption(QStringList() << "b" - << "best-match", + QCommandLineOption(QStringList() << "b" << "best-match", QObject::tr("Must match only one entry, otherwise a list of possible matches is shown.")); Clip::Clip() @@ -72,7 +69,7 @@ int Clip::executeWithDatabase(QSharedPointer database, QSharedPointer< bool ok; timeout = args.at(2).toInt(&ok); if (!ok) { - err << QObject::tr("Invalid timeout value %1.").arg(args.at(2)) << endl; + err << QObject::tr("Invalid timeout value %1.").arg(args.at(2)) << Qt::endl; return EXIT_FAILURE; } } @@ -83,14 +80,14 @@ int Clip::executeWithDatabase(QSharedPointer database, QSharedPointer< const auto& searchTerm = args.at(1); const auto results = searcher.search(QString("title:%1").arg(searchTerm), database->rootGroup(), true); if (results.count() > 1) { - err << QObject::tr("Multiple entries matching:") << endl; + err << QObject::tr("Multiple entries matching:") << Qt::endl; for (const Entry* result : results) { - err << result->path().prepend('/') << endl; + err << result->path().prepend('/') << Qt::endl; } return EXIT_FAILURE; } else { entryPath = (results.isEmpty()) ? searchTerm : results[0]->path().prepend('/'); - out << QObject::tr("Using matching entry: %1").arg(entryPath) << endl; + out << QObject::tr("Using matching entry: %1").arg(entryPath) << Qt::endl; } } else { entryPath = args.at(1); @@ -98,12 +95,12 @@ int Clip::executeWithDatabase(QSharedPointer database, QSharedPointer< auto* entry = database->rootGroup()->findEntryByPath(entryPath); if (!entry) { - err << QObject::tr("Entry %1 not found.").arg(entryPath) << endl; + err << QObject::tr("Entry %1 not found.").arg(entryPath) << Qt::endl; return EXIT_FAILURE; } if (parser->isSet(AttributeOption) && parser->isSet(TotpOption)) { - err << QObject::tr("ERROR: Please specify one of --attribute or --totp, not both.") << endl; + err << QObject::tr("ERROR: Please specify one of --attribute or --totp, not both.") << Qt::endl; return EXIT_FAILURE; } @@ -112,7 +109,7 @@ int Clip::executeWithDatabase(QSharedPointer database, QSharedPointer< bool found = false; if (parser->isSet(TotpOption) || selectedAttribute == "totp") { if (!entry->hasTotp()) { - err << QObject::tr("Entry with path %1 has no TOTP set up.").arg(entryPath) << endl; + err << QObject::tr("Entry with path %1 has no TOTP set up.").arg(entryPath) << Qt::endl; return EXIT_FAILURE; } @@ -127,7 +124,7 @@ int Clip::executeWithDatabase(QSharedPointer database, QSharedPointer< if (attrs.size() > 1) { err << QObject::tr("ERROR: attribute %1 is ambiguous, it matches %2.") .arg(selectedAttribute, QLocale().createSeparatedList(attrs)) - << endl; + << Qt::endl; return EXIT_FAILURE; } else if (attrs.size() == 1) { found = true; @@ -137,7 +134,7 @@ int Clip::executeWithDatabase(QSharedPointer database, QSharedPointer< } if (!found) { - out << QObject::tr("Attribute \"%1\" not found.").arg(selectedAttribute) << endl; + out << QObject::tr("Attribute \"%1\" not found.").arg(selectedAttribute) << Qt::endl; return EXIT_FAILURE; } @@ -146,7 +143,7 @@ int Clip::executeWithDatabase(QSharedPointer database, QSharedPointer< return exitCode; } - out << QObject::tr("Entry's \"%1\" attribute copied to the clipboard!").arg(selectedAttribute) << endl; + out << QObject::tr("Entry's \"%1\" attribute copied to the clipboard!").arg(selectedAttribute) << Qt::endl; if (timeout <= 0) { return exitCode; @@ -156,13 +153,13 @@ int Clip::executeWithDatabase(QSharedPointer database, QSharedPointer< while (timeout > 0) { out << '\r' << QString(lastLine.size(), ' ') << '\r'; lastLine = QObject::tr("Clearing the clipboard in %1 second(s)...", "", timeout).arg(timeout); - out << lastLine << flush; + out << lastLine << Qt::flush; Tools::sleep(1000); --timeout; } Utils::clipText(""); out << '\r' << QString(lastLine.size(), ' ') << '\r'; - out << QObject::tr("Clipboard cleared!") << endl; + out << QObject::tr("Clipboard cleared!") << Qt::endl; return EXIT_SUCCESS; } diff --git a/src/cli/Command.cpp b/src/cli/Command.cpp index 4bba8fff9..ae1020086 100644 --- a/src/cli/Command.cpp +++ b/src/cli/Command.cpp @@ -56,12 +56,10 @@ const QCommandLineOption Command::HelpOption = QCommandLineOption(QStringList() QObject::tr("Display this help.")); const QCommandLineOption Command::QuietOption = - QCommandLineOption(QStringList() << "q" - << "quiet", + QCommandLineOption(QStringList() << "q" << "quiet", QObject::tr("Silence password prompt and other secondary outputs.")); -const QCommandLineOption Command::KeyFileOption = QCommandLineOption(QStringList() << "k" - << "key-file", +const QCommandLineOption Command::KeyFileOption = QCommandLineOption(QStringList() << "k" << "key-file", QObject::tr("Key file of the database."), QObject::tr("path")); @@ -69,8 +67,7 @@ const QCommandLineOption Command::NoPasswordOption = QCommandLineOption(QStringList() << "no-password", QObject::tr("Deactivate password key for the database.")); const QCommandLineOption Command::YubiKeyOption = - QCommandLineOption(QStringList() << "y" - << "yubikey", + QCommandLineOption(QStringList() << "y" << "yubikey", QObject::tr("Yubikey slot and optional serial used to access the database (e.g., 1:7370001)."), QObject::tr("slot[:serial]")); @@ -103,9 +100,7 @@ Command::Command() options.append(Command::QuietOption); } -Command::~Command() -{ -} +Command::~Command() = default; QString Command::getDescriptionLine() { diff --git a/src/cli/DatabaseCreate.cpp b/src/cli/DatabaseCreate.cpp index adebda4c3..de7b99b06 100644 --- a/src/cli/DatabaseCreate.cpp +++ b/src/cli/DatabaseCreate.cpp @@ -18,14 +18,14 @@ #include "DatabaseCreate.h" #include "Utils.h" +#include "core/Global.h" #include "keys/FileKey.h" #include #include const QCommandLineOption DatabaseCreate::DecryptionTimeOption = - QCommandLineOption(QStringList() << "t" - << "decryption-time", + QCommandLineOption(QStringList() << "t" << "decryption-time", QObject::tr("Target decryption time in MS for the database."), QObject::tr("time")); @@ -40,9 +40,7 @@ const QCommandLineOption DatabaseCreate::SetKeyFileOption = QObject::tr("path")); const QCommandLineOption DatabaseCreate::SetPasswordOption = - QCommandLineOption(QStringList() << "p" - << "set-password", - QObject::tr("Set a password for the database.")); + QCommandLineOption(QStringList() << "p" << "set-password", QObject::tr("Set a password for the database.")); DatabaseCreate::DatabaseCreate() { @@ -70,13 +68,13 @@ QSharedPointer DatabaseCreate::initializeDatabaseFromOptions(const QSh if (decryptionTimeValue.length() != 0) { decryptionTime = decryptionTimeValue.toInt(); if (decryptionTime <= 0) { - err << QObject::tr("Invalid decryption time %1.").arg(decryptionTimeValue) << endl; + err << QObject::tr("Invalid decryption time %1.").arg(decryptionTimeValue) << Qt::endl; return {}; } if (decryptionTime < Kdf::MIN_ENCRYPTION_TIME || decryptionTime > Kdf::MAX_ENCRYPTION_TIME) { err << QObject::tr("Target decryption time must be between %1 and %2.") .arg(QString::number(Kdf::MIN_ENCRYPTION_TIME), QString::number(Kdf::MAX_ENCRYPTION_TIME)) - << endl; + << Qt::endl; return {}; } } @@ -86,7 +84,7 @@ QSharedPointer DatabaseCreate::initializeDatabaseFromOptions(const QSh if (parser->isSet(DatabaseCreate::SetPasswordOption)) { auto passwordKey = Utils::getConfirmedPassword(); if (passwordKey.isNull()) { - err << QObject::tr("Failed to set database password.") << endl; + err << QObject::tr("Failed to set database password.") << Qt::endl; return {}; } key->addKey(passwordKey); @@ -104,7 +102,7 @@ QSharedPointer DatabaseCreate::initializeDatabaseFromOptions(const QSh } if (!Utils::loadFileKey(keyFilePath, fileKey)) { - err << QObject::tr("Loading the key file failed") << endl; + err << QObject::tr("Loading the key file failed") << Qt::endl; return {}; } @@ -114,7 +112,7 @@ QSharedPointer DatabaseCreate::initializeDatabaseFromOptions(const QSh } if (key->isEmpty()) { - err << QObject::tr("No key is set. Aborting database creation.") << endl; + err << QObject::tr("No key is set. Aborting database creation.") << Qt::endl; return {}; } @@ -125,15 +123,15 @@ QSharedPointer DatabaseCreate::initializeDatabaseFromOptions(const QSh auto kdf = db->kdf(); Q_ASSERT(kdf); - out << QObject::tr("Benchmarking key derivation function for %1ms delay.").arg(decryptionTimeValue) << endl; + out << QObject::tr("Benchmarking key derivation function for %1ms delay.").arg(decryptionTimeValue) << Qt::endl; int rounds = kdf->benchmark(decryptionTime); - out << QObject::tr("Setting %1 rounds for key derivation function.").arg(QString::number(rounds)) << endl; + out << QObject::tr("Setting %1 rounds for key derivation function.").arg(QString::number(rounds)) << Qt::endl; kdf->setRounds(rounds); bool ok = db->changeKdf(kdf); if (!ok) { - err << QObject::tr("error while setting database key derivation settings.") << endl; + err << QObject::tr("error while setting database key derivation settings.") << Qt::endl; return {}; } } @@ -149,7 +147,7 @@ QSharedPointer DatabaseCreate::initializeDatabaseFromOptions(const QSh * If a key file is specified but it can't be loaded, the function will * fail. * - * If the database is being saved in a non existant directory, the + * If the database is being saved in a non existent directory, the * function will fail. * * @return EXIT_SUCCESS on success, or EXIT_FAILURE on failure @@ -168,7 +166,7 @@ int DatabaseCreate::execute(const QStringList& arguments) const QString& databaseFilename = args.at(0); if (QFileInfo::exists(databaseFilename)) { - err << QObject::tr("File %1 already exists.").arg(databaseFilename) << endl; + err << QObject::tr("File %1 already exists.").arg(databaseFilename) << Qt::endl; return EXIT_FAILURE; } @@ -179,10 +177,10 @@ int DatabaseCreate::execute(const QStringList& arguments) QString errorMessage; if (!db->saveAs(databaseFilename, Database::Atomic, {}, &errorMessage)) { - err << QObject::tr("Failed to save the database: %1.").arg(errorMessage) << endl; + err << QObject::tr("Failed to save the database: %1.").arg(errorMessage) << Qt::endl; return EXIT_FAILURE; } - out << QObject::tr("Successfully created new database.") << endl; + out << QObject::tr("Successfully created new database.") << Qt::endl; return EXIT_SUCCESS; } diff --git a/src/cli/DatabaseEdit.cpp b/src/cli/DatabaseEdit.cpp index f5ca4ef2e..3df4d4b19 100644 --- a/src/cli/DatabaseEdit.cpp +++ b/src/cli/DatabaseEdit.cpp @@ -19,6 +19,7 @@ #include "Utils.h" #include "cli/DatabaseCreate.h" +#include "core/Global.h" #include "keys/ChallengeResponseKey.h" #include "keys/FileKey.h" #include "keys/PasswordKey.h" @@ -53,7 +54,7 @@ int DatabaseEdit::executeWithDatabase(QSharedPointer database, QShared err << QObject::tr("Cannot use %1 and %2 at the same time.") .arg(DatabaseCreate::SetPasswordOption.names().at(0)) .arg(DatabaseEdit::UnsetPasswordOption.names().at(0)) - << endl; + << Qt::endl; return EXIT_FAILURE; } @@ -61,7 +62,7 @@ int DatabaseEdit::executeWithDatabase(QSharedPointer database, QShared err << QObject::tr("Cannot use %1 and %2 at the same time.") .arg(DatabaseCreate::SetKeyFileOption.names().at(0)) .arg(DatabaseEdit::UnsetKeyFileOption.names().at(0)) - << endl; + << Qt::endl; return EXIT_FAILURE; } @@ -76,7 +77,7 @@ int DatabaseEdit::executeWithDatabase(QSharedPointer database, QShared parser->value(DatabaseCreate::SetKeyFileOption), parser->isSet(DatabaseEdit::UnsetKeyFileOption)); if (newDatabaseKey.isNull()) { - err << QObject::tr("Could not change the database key.") << endl; + err << QObject::tr("Could not change the database key.") << Qt::endl; return EXIT_FAILURE; } database->setKey(newDatabaseKey); @@ -84,17 +85,17 @@ int DatabaseEdit::executeWithDatabase(QSharedPointer database, QShared } if (!databaseWasChanged) { - out << QObject::tr("Database was not modified.") << endl; + out << QObject::tr("Database was not modified.") << Qt::endl; return EXIT_SUCCESS; } QString errorMessage; if (!database->save(Database::Atomic, {}, &errorMessage)) { - err << QObject::tr("Writing the database failed: %1").arg(errorMessage) << endl; + err << QObject::tr("Writing the database failed: %1").arg(errorMessage) << Qt::endl; return EXIT_FAILURE; } - out << QObject::tr("Successfully edited the database.") << endl; + out << QObject::tr("Successfully edited the database.") << Qt::endl; return EXIT_SUCCESS; } @@ -113,19 +114,19 @@ QSharedPointer DatabaseEdit::getNewDatabaseKey(QSharedPointerkey()->getChallengeResponseKey(ChallengeResponseKey::UUID); if (removePassword && currentPasswordKey.isNull()) { - err << QObject::tr("Cannot remove password: The database does not have a password.") << endl; + err << QObject::tr("Cannot remove password: The database does not have a password.") << Qt::endl; return {}; } if (removeKeyFile && currentFileKey.isNull()) { - err << QObject::tr("Cannot remove file key: The database does not have a file key.") << endl; + err << QObject::tr("Cannot remove file key: The database does not have a file key.") << Qt::endl; return {}; } if (updatePassword) { QSharedPointer newPasswordKey = Utils::getConfirmedPassword(); if (newPasswordKey.isNull()) { - err << QObject::tr("Failed to set database password.") << endl; + err << QObject::tr("Failed to set database password.") << Qt::endl; return {}; } newDatabaseKey->addKey(newPasswordKey); @@ -137,7 +138,7 @@ QSharedPointer DatabaseEdit::getNewDatabaseKey(QSharedPointer newFileKey = QSharedPointer::create(); QString errorMessage; if (!Utils::loadFileKey(newFileKeyPath, newFileKey)) { - err << QObject::tr("Loading the new key file failed: %1").arg(errorMessage) << endl; + err << QObject::tr("Loading the new key file failed: %1").arg(errorMessage) << Qt::endl; return {}; } newDatabaseKey->addKey(newFileKey); @@ -150,13 +151,13 @@ QSharedPointer DatabaseEdit::getNewDatabaseKey(QSharedPointer& key : database->key()->keys()) { if (key->uuid() != PasswordKey::UUID && key->uuid() != FileKey::UUID) { - err << QObject::tr("Found unexpected Key type %1").arg(key->uuid().toString()) << endl; + err << QObject::tr("Found unexpected Key type %1").arg(key->uuid().toString()) << Qt::endl; return {}; } } for (const QSharedPointer& key : database->key()->challengeResponseKeys()) { if (key->uuid() != ChallengeResponseKey::UUID) { - err << QObject::tr("Found unexpected Key type %1").arg(key->uuid().toString()) << endl; + err << QObject::tr("Found unexpected Key type %1").arg(key->uuid().toString()) << Qt::endl; return {}; } } @@ -166,7 +167,7 @@ QSharedPointer DatabaseEdit::getNewDatabaseKey(QSharedPointerkeys().isEmpty() && newDatabaseKey->challengeResponseKeys().isEmpty()) { - err << QObject::tr("Cannot remove all the keys from a database.") << endl; + err << QObject::tr("Cannot remove all the keys from a database.") << Qt::endl; return {}; } diff --git a/src/cli/DatabaseInfo.cpp b/src/cli/DatabaseInfo.cpp index f0e5e0f03..0b205157c 100644 --- a/src/cli/DatabaseInfo.cpp +++ b/src/cli/DatabaseInfo.cpp @@ -18,6 +18,7 @@ #include "DatabaseInfo.h" #include "Utils.h" +#include "core/Clock.h" #include "core/DatabaseStats.h" #include "core/Global.h" #include "core/Group.h" @@ -35,39 +36,39 @@ int DatabaseInfo::executeWithDatabase(QSharedPointer database, QShared { auto& out = Utils::STDOUT; - out << QObject::tr("UUID: ") << database->uuid().toString() << endl; - out << QObject::tr("Name: ") << database->metadata()->name() << endl; - out << QObject::tr("Description: ") << database->metadata()->description() << endl; + out << QObject::tr("UUID: ") << database->uuid().toString() << Qt::endl; + out << QObject::tr("Name: ") << database->metadata()->name() << Qt::endl; + out << QObject::tr("Description: ") << database->metadata()->description() << Qt::endl; for (auto& cipher : asConst(KeePass2::CIPHERS)) { if (cipher == database->cipher()) { - out << QObject::tr("Cipher: ") << KeePass2::cipherToString(cipher) << endl; + out << QObject::tr("Cipher: ") << KeePass2::cipherToString(cipher) << Qt::endl; } } - out << QObject::tr("KDF: ") << database->kdf()->toString() << endl; + out << QObject::tr("KDF: ") << database->kdf()->toString() << Qt::endl; if (database->metadata()->recycleBinEnabled()) { - out << QObject::tr("Recycle bin is enabled.") << endl; + out << QObject::tr("Recycle bin is enabled.") << Qt::endl; } else { - out << QObject::tr("Recycle bin is not enabled.") << endl; + out << QObject::tr("Recycle bin is not enabled.") << Qt::endl; } DatabaseStats stats(database); - out << QObject::tr("Location") << ": " << database->filePath() << endl; - out << QObject::tr("Database created") << ": " - << database->rootGroup()->timeInfo().creationTime().toString(Qt::DefaultLocaleShortDate) << endl; - out << QObject::tr("Last saved") << ": " << stats.modified.toString(Qt::DefaultLocaleShortDate) << endl; + out << QObject::tr("Location") << ": " << database->filePath() << Qt::endl; + out << QObject::tr("Database created") << ": " << Clock::toString(database->rootGroup()->timeInfo().creationTime()) + << Qt::endl; + out << QObject::tr("Last saved") << ": " << Clock::toString(stats.modified) << Qt::endl; out << QObject::tr("Unsaved changes") << ": " << (database->isModified() ? QObject::tr("yes") : QObject::tr("no")) - << endl; - out << QObject::tr("Number of groups") << ": " << QString::number(stats.groupCount) << endl; - out << QObject::tr("Number of entries") << ": " << QString::number(stats.entryCount) << endl; - out << QObject::tr("Number of expired entries") << ": " << QString::number(stats.expiredEntries) << endl; - out << QObject::tr("Unique passwords") << ": " << QString::number(stats.uniquePasswords) << endl; - out << QObject::tr("Non-unique passwords") << ": " << QString::number(stats.reusedPasswords) << endl; - out << QObject::tr("Maximum password reuse") << ": " << QString::number(stats.maxPwdReuse()) << endl; - out << QObject::tr("Number of short passwords") << ": " << QString::number(stats.shortPasswords) << endl; - out << QObject::tr("Number of weak passwords") << ": " << QString::number(stats.weakPasswords) << endl; - out << QObject::tr("Entries excluded from reports") << ": " << QString::number(stats.excludedEntries) << endl; + << Qt::endl; + out << QObject::tr("Number of groups") << ": " << QString::number(stats.groupCount) << Qt::endl; + out << QObject::tr("Number of entries") << ": " << QString::number(stats.entryCount) << Qt::endl; + out << QObject::tr("Number of expired entries") << ": " << QString::number(stats.expiredEntries) << Qt::endl; + out << QObject::tr("Unique passwords") << ": " << QString::number(stats.uniquePasswords) << Qt::endl; + out << QObject::tr("Non-unique passwords") << ": " << QString::number(stats.reusedPasswords) << Qt::endl; + out << QObject::tr("Maximum password reuse") << ": " << QString::number(stats.maxPwdReuse()) << Qt::endl; + out << QObject::tr("Number of short passwords") << ": " << QString::number(stats.shortPasswords) << Qt::endl; + out << QObject::tr("Number of weak passwords") << ": " << QString::number(stats.weakPasswords) << Qt::endl; + out << QObject::tr("Entries excluded from reports") << ": " << QString::number(stats.excludedEntries) << Qt::endl; out << QObject::tr("Average password length") << ": " << QObject::tr("%1 characters").arg(stats.averagePwdLength()) - << endl; + << Qt::endl; return EXIT_SUCCESS; } diff --git a/src/cli/DatabaseInfo.h b/src/cli/DatabaseInfo.h index b7e959cc3..42a48c86f 100644 --- a/src/cli/DatabaseInfo.h +++ b/src/cli/DatabaseInfo.h @@ -25,7 +25,7 @@ class DatabaseInfo : public DatabaseCommand public: DatabaseInfo(); - int executeWithDatabase(QSharedPointer db, QSharedPointer parser); + int executeWithDatabase(QSharedPointer db, QSharedPointer parser) override; }; #endif // KEEPASSXC_DATABASEINFO_H diff --git a/src/cli/Diceware.cpp b/src/cli/Diceware.cpp index b6a65bd1e..9b5cc2ed6 100644 --- a/src/cli/Diceware.cpp +++ b/src/cli/Diceware.cpp @@ -18,19 +18,18 @@ #include "Diceware.h" #include "Utils.h" +#include "core/Global.h" #include "core/PassphraseGenerator.h" #include const QCommandLineOption Diceware::WordCountOption = - QCommandLineOption(QStringList() << "W" - << "words", + QCommandLineOption(QStringList() << "W" << "words", QObject::tr("Word count for the diceware passphrase."), QObject::tr("count", "CLI parameter")); const QCommandLineOption Diceware::WordListOption = - QCommandLineOption(QStringList() << "w" - << "word-list", + QCommandLineOption(QStringList() << "w" << "word-list", QObject::tr("Wordlist for the diceware generator.\n[Default: EFF English]"), QObject::tr("path")); @@ -58,7 +57,7 @@ int Diceware::execute(const QStringList& arguments) if (wordCount.isEmpty()) { dicewareGenerator.setWordCount(PassphraseGenerator::DefaultWordCount); } else if (wordCount.toInt() <= 0) { - err << QObject::tr("Invalid word count %1").arg(wordCount) << endl; + err << QObject::tr("Invalid word count %1").arg(wordCount) << Qt::endl; return EXIT_FAILURE; } else { dicewareGenerator.setWordCount(wordCount.toInt()); @@ -69,15 +68,13 @@ int Diceware::execute(const QStringList& arguments) dicewareGenerator.setWordList(wordListFile); } - if (!dicewareGenerator.isValid()) { - // We already validated the word count input so if the generator is invalid, it - // must be because the word list is too small. - err << QObject::tr("The word list is too small (< 1000 items)") << endl; - return EXIT_FAILURE; + // Show a warning if the wordlist is smaller than the recommended size + if (!dicewareGenerator.isWordListValid()) { + err << QObject::tr("Warning: the chosen wordlist is smaller than the minimum recommended size!") << Qt::endl; } QString password = dicewareGenerator.generatePassphrase(); - out << password << endl; + out << password << Qt::endl; return EXIT_SUCCESS; } diff --git a/src/cli/Edit.cpp b/src/cli/Edit.cpp index 1154ce309..680b45f0b 100644 --- a/src/cli/Edit.cpp +++ b/src/cli/Edit.cpp @@ -20,15 +20,14 @@ #include "Add.h" #include "Generate.h" #include "Utils.h" +#include "core/Global.h" #include "core/Group.h" #include "core/PasswordGenerator.h" #include -const QCommandLineOption Edit::TitleOption = QCommandLineOption(QStringList() << "t" - << "title", - QObject::tr("Title for the entry."), - QObject::tr("title")); +const QCommandLineOption Edit::TitleOption = + QCommandLineOption(QStringList() << "t" << "title", QObject::tr("Title for the entry."), QObject::tr("title")); Edit::Edit() { @@ -66,7 +65,7 @@ int Edit::executeWithDatabase(QSharedPointer database, QSharedPointer< // Cannot use those 2 options at the same time! if (parser->isSet(Add::GenerateOption) && parser->isSet(Add::PasswordPromptOption)) { - err << QObject::tr("Cannot generate a password and prompt at the same time.") << endl; + err << QObject::tr("Cannot generate a password and prompt at the same time.") << Qt::endl; return EXIT_FAILURE; } @@ -83,7 +82,7 @@ int Edit::executeWithDatabase(QSharedPointer database, QSharedPointer< Entry* entry = database->rootGroup()->findEntryByPath(entryPath); if (!entry) { - err << QObject::tr("Could not find entry with path %1.").arg(entryPath) << endl; + err << QObject::tr("Could not find entry with path %1.").arg(entryPath) << Qt::endl; return EXIT_FAILURE; } @@ -93,7 +92,7 @@ int Edit::executeWithDatabase(QSharedPointer database, QSharedPointer< QString title = parser->value(Edit::TitleOption); bool prompt = parser->isSet(Add::PasswordPromptOption); if (username.isEmpty() && url.isEmpty() && notes.isEmpty() && title.isEmpty() && !prompt && !generate) { - err << QObject::tr("Not changing any field for entry %1.").arg(entryPath) << endl; + err << QObject::tr("Not changing any field for entry %1.").arg(entryPath) << Qt::endl; return EXIT_FAILURE; } @@ -116,7 +115,7 @@ int Edit::executeWithDatabase(QSharedPointer database, QSharedPointer< } if (prompt) { - out << QObject::tr("Enter new password for entry: ") << flush; + out << QObject::tr("Enter new password for entry: ") << Qt::flush; QString password = Utils::getPassword(parser->isSet(Command::QuietOption)); entry->setPassword(password); } else if (generate) { @@ -128,10 +127,10 @@ int Edit::executeWithDatabase(QSharedPointer database, QSharedPointer< QString errorMessage; if (!database->save(Database::Atomic, {}, &errorMessage)) { - err << QObject::tr("Writing the database failed: %1").arg(errorMessage) << endl; + err << QObject::tr("Writing the database failed: %1").arg(errorMessage) << Qt::endl; return EXIT_FAILURE; } - out << QObject::tr("Successfully edited entry %1.").arg(entry->title()) << endl; + out << QObject::tr("Successfully edited entry %1.").arg(entry->title()) << Qt::endl; return EXIT_SUCCESS; } diff --git a/src/cli/Estimate.cpp b/src/cli/Estimate.cpp index 094fcf36c..b264967f0 100644 --- a/src/cli/Estimate.cpp +++ b/src/cli/Estimate.cpp @@ -18,15 +18,14 @@ #include "Estimate.h" #include "Utils.h" +#include "core/Global.h" #include "core/PasswordHealth.h" #include #include const QCommandLineOption Estimate::AdvancedOption = - QCommandLineOption(QStringList() << "a" - << "advanced", - QObject::tr("Perform advanced analysis on the password.")); + QCommandLineOption(QStringList() << "a" << "advanced", QObject::tr("Perform advanced analysis on the password.")); Estimate::Estimate() { @@ -41,13 +40,13 @@ static void estimate(const char* pwd, bool advanced) { auto& out = Utils::STDOUT; - int len = static_cast(strlen(pwd)); + auto len = static_cast(strlen(pwd)); if (!advanced) { const auto e = PasswordHealth(pwd).entropy(); // clang-format off out << QObject::tr("Length %1").arg(len, 0) << '\t' << QObject::tr("Entropy %1").arg(e, 0, 'f', 3) << '\t' - << QObject::tr("Log10 %1").arg(e * 0.301029996, 0, 'f', 3) << endl; + << QObject::tr("Log10 %1").arg(e * 0.301029996, 0, 'f', 3) << Qt::endl; // clang-format on } else { int pwdLen = 0; @@ -62,7 +61,7 @@ static void estimate(const char* pwd, bool advanced) out << QObject::tr("Length %1").arg(len) << '\t' << QObject::tr("Entropy %1").arg(e, 0, 'f', 3) << '\t' << QObject::tr("Log10 %1").arg(e * 0.301029996, 0, 'f', 3) << "\n " - << QObject::tr("Multi-word extra bits %1").arg(m, 0, 'f', 1) << endl; + << QObject::tr("Multi-word extra bits %1").arg(m, 0, 'f', 1) << Qt::endl; // clang-format on p = info; pwdLen = 0; @@ -135,13 +134,13 @@ static void estimate(const char* pwd, bool advanced) for (n = 0; n < p->Length; ++n, ++pwd) { out << *pwd; } - out << endl; + out << Qt::endl; p = p->Next; } ZxcvbnFreeInfo(info); if (pwdLen != len) { out << QObject::tr("*** Password length (%1) != sum of length of parts (%2) ***").arg(len).arg(pwdLen) - << endl; + << Qt::endl; } } } diff --git a/src/cli/Export.cpp b/src/cli/Export.cpp index 6456fe5b1..36b38b1de 100644 --- a/src/cli/Export.cpp +++ b/src/cli/Export.cpp @@ -19,15 +19,16 @@ #include "TextStream.h" #include "Utils.h" +#include "core/Global.h" #include "format/CsvExporter.h" +#include "format/HtmlExporter.h" #include const QCommandLineOption Export::FormatOption = QCommandLineOption( - QStringList() << "f" - << "format", - QObject::tr("Format to use when exporting. Available choices are 'xml' or 'csv'. Defaults to 'xml'."), - QStringLiteral("xml|csv")); + QStringList() << "f" << "format", + QObject::tr("Format to use when exporting. Available choices are 'xml', 'csv' or 'html'. Defaults to 'xml'."), + QStringLiteral("xml|csv|html")); Export::Export() { @@ -46,15 +47,18 @@ int Export::executeWithDatabase(QSharedPointer database, QSharedPointe QByteArray xmlData; QString errorMessage; if (!database->extract(xmlData, &errorMessage)) { - err << QObject::tr("Unable to export database to XML: %1").arg(errorMessage) << endl; + err << QObject::tr("Unable to export database to XML: %1").arg(errorMessage) << Qt::endl; return EXIT_FAILURE; } out.write(xmlData.constData()); } else if (format.startsWith(QStringLiteral("csv"), Qt::CaseInsensitive)) { CsvExporter csvExporter; out << csvExporter.exportDatabase(database); + } else if (format.startsWith(QStringLiteral("html"), Qt::CaseInsensitive)) { + HtmlExporter htmlExporter; + out << htmlExporter.exportDatabase(database); } else { - err << QObject::tr("Unsupported format %1").arg(format) << endl; + err << QObject::tr("Unsupported format %1").arg(format) << Qt::endl; return EXIT_FAILURE; } diff --git a/src/cli/Generate.cpp b/src/cli/Generate.cpp index 8ce1a6116..258ce79fa 100644 --- a/src/cli/Generate.cpp +++ b/src/cli/Generate.cpp @@ -18,46 +18,36 @@ #include "Generate.h" #include "Utils.h" +#include "core/Global.h" #include "core/PasswordGenerator.h" #include const QCommandLineOption Generate::PasswordLengthOption = - QCommandLineOption(QStringList() << "L" - << "length", + QCommandLineOption(QStringList() << "L" << "length", QObject::tr("Length of the generated password"), QObject::tr("length")); -const QCommandLineOption Generate::LowerCaseOption = QCommandLineOption(QStringList() << "l" - << "lower", - QObject::tr("Use lowercase characters")); +const QCommandLineOption Generate::LowerCaseOption = + QCommandLineOption(QStringList() << "l" << "lower", QObject::tr("Use lowercase characters")); -const QCommandLineOption Generate::UpperCaseOption = QCommandLineOption(QStringList() << "U" - << "upper", - QObject::tr("Use uppercase characters")); +const QCommandLineOption Generate::UpperCaseOption = + QCommandLineOption(QStringList() << "U" << "upper", QObject::tr("Use uppercase characters")); -const QCommandLineOption Generate::NumbersOption = QCommandLineOption(QStringList() << "n" - << "numeric", - QObject::tr("Use numbers")); +const QCommandLineOption Generate::NumbersOption = + QCommandLineOption(QStringList() << "n" << "numeric", QObject::tr("Use numbers")); -const QCommandLineOption Generate::SpecialCharsOption = QCommandLineOption(QStringList() << "s" - << "special", - QObject::tr("Use special characters")); +const QCommandLineOption Generate::SpecialCharsOption = + QCommandLineOption(QStringList() << "s" << "special", QObject::tr("Use special characters")); -const QCommandLineOption Generate::ExtendedAsciiOption = QCommandLineOption(QStringList() << "e" - << "extended", - QObject::tr("Use extended ASCII")); +const QCommandLineOption Generate::ExtendedAsciiOption = + QCommandLineOption(QStringList() << "e" << "extended", QObject::tr("Use extended ASCII")); -const QCommandLineOption Generate::ExcludeCharsOption = QCommandLineOption(QStringList() << "x" - << "exclude", - QObject::tr("Exclude character set"), - QObject::tr("chars")); +const QCommandLineOption Generate::ExcludeCharsOption = + QCommandLineOption(QStringList() << "x" << "exclude", QObject::tr("Exclude character set"), QObject::tr("chars")); const QCommandLineOption Generate::CustomCharacterSetOption = - QCommandLineOption(QStringList() << "c" - << "custom", - QObject::tr("Use custom character set"), - QObject::tr("chars")); + QCommandLineOption(QStringList() << "c" << "custom", QObject::tr("Use custom character set"), QObject::tr("chars")); const QCommandLineOption Generate::ExcludeSimilarCharsOption = QCommandLineOption(QStringList() << "exclude-similar", QObject::tr("Exclude similar looking characters")); @@ -92,13 +82,13 @@ QSharedPointer Generate::createGenerator(QSharedPointersetLength(PasswordGenerator::DefaultLength); } else if (passwordLength.toInt() <= 0) { - err << QObject::tr("Invalid password length %1").arg(passwordLength) << endl; - return QSharedPointer(nullptr); + err << QObject::tr("Invalid password length %1").arg(passwordLength) << Qt::endl; + return {}; } else { passwordGenerator->setLength(passwordLength.toInt()); } - PasswordGenerator::CharClasses classes = 0x0; + PasswordGenerator::CharClasses classes; if (parser->isSet(Generate::LowerCaseOption)) { classes |= PasswordGenerator::LowerLetters; @@ -116,7 +106,7 @@ QSharedPointer Generate::createGenerator(QSharedPointerisSet(Generate::ExcludeSimilarCharsOption)) { flags |= PasswordGenerator::ExcludeLookAlike; @@ -138,8 +128,8 @@ QSharedPointer Generate::createGenerator(QSharedPointersetExcludedCharacterSet(parser->value(Generate::ExcludeCharsOption)); if (!passwordGenerator->isValid()) { - err << QObject::tr("Invalid password generator after applying all options") << endl; - return QSharedPointer(nullptr); + err << QObject::tr("Invalid password generator after applying all options") << Qt::endl; + return {}; } return passwordGenerator; @@ -159,7 +149,7 @@ int Generate::execute(const QStringList& arguments) auto& out = Utils::STDOUT; QString password = passwordGenerator->generatePassword(); - out << password << endl; + out << password << Qt::endl; return EXIT_SUCCESS; } diff --git a/src/cli/Import.cpp b/src/cli/Import.cpp index cc74df767..48f93d88c 100644 --- a/src/cli/Import.cpp +++ b/src/cli/Import.cpp @@ -20,6 +20,8 @@ #include "DatabaseCreate.h" #include "Utils.h" +#include "core/Global.h" + #include #include @@ -28,7 +30,7 @@ * A password can be specified to encrypt the database. * If none is specified the function will fail. * - * If the database is being saved in a non existant directory, the + * If the database is being saved in a non existent directory, the * function will fail. * * @return EXIT_SUCCESS on success, or EXIT_FAILURE on failure @@ -61,7 +63,7 @@ int Import::execute(const QStringList& arguments) const QString& dbPath = args.at(1); if (QFileInfo::exists(dbPath)) { - err << QObject::tr("File %1 already exists.").arg(dbPath) << endl; + err << QObject::tr("File %1 already exists.").arg(dbPath) << Qt::endl; return EXIT_FAILURE; } @@ -72,15 +74,15 @@ int Import::execute(const QStringList& arguments) QString errorMessage; if (!db->import(xmlExportPath, &errorMessage)) { - err << QObject::tr("Unable to import XML database: %1").arg(errorMessage) << endl; + err << QObject::tr("Unable to import XML database: %1").arg(errorMessage) << Qt::endl; return EXIT_FAILURE; } if (!db->saveAs(dbPath, Database::Atomic, {}, &errorMessage)) { - err << QObject::tr("Failed to save the database: %1.").arg(errorMessage) << endl; + err << QObject::tr("Failed to save the database: %1.").arg(errorMessage) << Qt::endl; return EXIT_FAILURE; } - out << QObject::tr("Successfully imported database.") << endl; + out << QObject::tr("Successfully imported database.") << Qt::endl; return EXIT_SUCCESS; } diff --git a/src/cli/List.cpp b/src/cli/List.cpp index 4140c1cd8..89ddef5be 100644 --- a/src/cli/List.cpp +++ b/src/cli/List.cpp @@ -18,18 +18,16 @@ #include "List.h" #include "Utils.h" +#include "core/Global.h" #include "core/Group.h" #include const QCommandLineOption List::RecursiveOption = - QCommandLineOption(QStringList() << "R" - << "recursive", - QObject::tr("Recursively list the elements of the group.")); + QCommandLineOption(QStringList() << "R" << "recursive", QObject::tr("Recursively list the elements of the group.")); -const QCommandLineOption List::FlattenOption = QCommandLineOption(QStringList() << "f" - << "flatten", - QObject::tr("Flattens the output to single lines.")); +const QCommandLineOption List::FlattenOption = + QCommandLineOption(QStringList() << "f" << "flatten", QObject::tr("Flattens the output to single lines.")); List::List() { @@ -52,17 +50,17 @@ int List::executeWithDatabase(QSharedPointer database, QSharedPointer< // No group provided, defaulting to root group. if (args.size() == 1) { - out << database->rootGroup()->print(recursive, flatten) << flush; + out << database->rootGroup()->print(recursive, flatten) << Qt::flush; return EXIT_SUCCESS; } const QString& groupPath = args.at(1); Group* group = database->rootGroup()->findGroupByPath(groupPath); if (!group) { - err << QObject::tr("Cannot find group %1.").arg(groupPath) << endl; + err << QObject::tr("Cannot find group %1.").arg(groupPath) << Qt::endl; return EXIT_FAILURE; } - out << group->print(recursive, flatten) << flush; + out << group->print(recursive, flatten) << Qt::flush; return EXIT_SUCCESS; } diff --git a/src/cli/Merge.cpp b/src/cli/Merge.cpp index 410892c9f..6cf351c96 100644 --- a/src/cli/Merge.cpp +++ b/src/cli/Merge.cpp @@ -18,13 +18,13 @@ #include "Merge.h" #include "Utils.h" +#include "core/Global.h" #include "core/Merger.h" #include const QCommandLineOption Merge::SameCredentialsOption = - QCommandLineOption(QStringList() << "s" - << "same-credentials", + QCommandLineOption(QStringList() << "s" << "same-credentials", QObject::tr("Use the same credentials for both database files.")); const QCommandLineOption Merge::KeyFileFromOption = @@ -37,7 +37,7 @@ const QCommandLineOption Merge::NoPasswordFromOption = QObject::tr("Deactivate password key for the database to merge from.")); const QCommandLineOption Merge::DryRunOption = - QCommandLineOption(QStringList() << "dry-run", + QCommandLineOption(QStringList() << "d" << "dry-run", QObject::tr("Only print the changes detected by the merge operation.")); const QCommandLineOption Merge::YubiKeyFromOption(QStringList() << "yubikey-from", @@ -90,18 +90,18 @@ int Merge::executeWithDatabase(QSharedPointer database, QSharedPointer QStringList changeList = merger.merge(); for (auto& mergeChange : changeList) { - out << "\t" << mergeChange << endl; + out << "\t" << mergeChange << Qt::endl; } if (!changeList.isEmpty() && !parser->isSet(Merge::DryRunOption)) { QString errorMessage; if (!database->save(Database::Atomic, {}, &errorMessage)) { - err << QObject::tr("Unable to save database to file : %1").arg(errorMessage) << endl; + err << QObject::tr("Unable to save database to file : %1").arg(errorMessage) << Qt::endl; return EXIT_FAILURE; } - out << QObject::tr("Successfully merged %1 into %2.").arg(fromDatabasePath, toDatabasePath) << endl; + out << QObject::tr("Successfully merged %1 into %2.").arg(fromDatabasePath, toDatabasePath) << Qt::endl; } else { - out << QObject::tr("Database was not modified by merge operation.") << endl; + out << QObject::tr("Database was not modified by merge operation.") << Qt::endl; } return EXIT_SUCCESS; diff --git a/src/cli/Move.cpp b/src/cli/Move.cpp index a9ee78614..96407c680 100644 --- a/src/cli/Move.cpp +++ b/src/cli/Move.cpp @@ -18,6 +18,7 @@ #include "Move.h" #include "Utils.h" +#include "core/Global.h" #include "core/Group.h" #include @@ -30,9 +31,7 @@ Move::Move() positionalArguments.append({QString("group"), QObject::tr("Path of the destination group."), QString("")}); } -Move::~Move() -{ -} +Move::~Move() = default; int Move::executeWithDatabase(QSharedPointer database, QSharedPointer parser) { @@ -45,18 +44,18 @@ int Move::executeWithDatabase(QSharedPointer database, QSharedPointer< Entry* entry = database->rootGroup()->findEntryByPath(entryPath); if (!entry) { - err << QObject::tr("Could not find entry with path %1.").arg(entryPath) << endl; + err << QObject::tr("Could not find entry with path %1.").arg(entryPath) << Qt::endl; return EXIT_FAILURE; } Group* destinationGroup = database->rootGroup()->findGroupByPath(destinationPath); if (!destinationGroup) { - err << QObject::tr("Could not find group with path %1.").arg(destinationPath) << endl; + err << QObject::tr("Could not find group with path %1.").arg(destinationPath) << Qt::endl; return EXIT_FAILURE; } if (destinationGroup == entry->parent()) { - err << QObject::tr("Entry is already in group %1.").arg(destinationPath) << endl; + err << QObject::tr("Entry is already in group %1.").arg(destinationPath) << Qt::endl; return EXIT_FAILURE; } @@ -66,10 +65,10 @@ int Move::executeWithDatabase(QSharedPointer database, QSharedPointer< QString errorMessage; if (!database->save(Database::Atomic, {}, &errorMessage)) { - err << QObject::tr("Writing the database failed %1.").arg(errorMessage) << endl; + err << QObject::tr("Writing the database failed %1.").arg(errorMessage) << Qt::endl; return EXIT_FAILURE; } - out << QObject::tr("Successfully moved entry %1 to group %2.").arg(entry->title(), destinationPath) << endl; + out << QObject::tr("Successfully moved entry %1 to group %2.").arg(entry->title(), destinationPath) << Qt::endl; return EXIT_SUCCESS; } diff --git a/src/cli/Move.h b/src/cli/Move.h index c506085a5..e87b0c795 100644 --- a/src/cli/Move.h +++ b/src/cli/Move.h @@ -24,9 +24,9 @@ class Move : public DatabaseCommand { public: Move(); - ~Move(); + ~Move() override; - int executeWithDatabase(QSharedPointer db, QSharedPointer parser); + int executeWithDatabase(QSharedPointer db, QSharedPointer parser) override; }; #endif // KEEPASSXC_MOVE_H diff --git a/src/cli/Remove.cpp b/src/cli/Remove.cpp index 906a81410..cc70be7d1 100644 --- a/src/cli/Remove.cpp +++ b/src/cli/Remove.cpp @@ -18,6 +18,7 @@ #include "Remove.h" #include "Utils.h" +#include "core/Global.h" #include "core/Group.h" #include "core/Metadata.h" @@ -38,7 +39,7 @@ int Remove::executeWithDatabase(QSharedPointer database, QSharedPointe auto entryPath = parser->positionalArguments().at(1); QPointer entry = database->rootGroup()->findEntryByPath(entryPath); if (!entry) { - err << QObject::tr("Entry %1 not found.").arg(entryPath) << endl; + err << QObject::tr("Entry %1 not found.").arg(entryPath) << Qt::endl; return EXIT_FAILURE; } @@ -54,14 +55,14 @@ int Remove::executeWithDatabase(QSharedPointer database, QSharedPointe QString errorMessage; if (!database->save(Database::Atomic, {}, &errorMessage)) { - err << QObject::tr("Unable to save database to file: %1").arg(errorMessage) << endl; + err << QObject::tr("Unable to save database to file: %1").arg(errorMessage) << Qt::endl; return EXIT_FAILURE; } if (recycled) { - out << QObject::tr("Successfully recycled entry %1.").arg(entryTitle) << endl; + out << QObject::tr("Successfully recycled entry %1.").arg(entryTitle) << Qt::endl; } else { - out << QObject::tr("Successfully deleted entry %1.").arg(entryTitle) << endl; + out << QObject::tr("Successfully deleted entry %1.").arg(entryTitle) << Qt::endl; } return EXIT_SUCCESS; diff --git a/src/cli/Remove.h b/src/cli/Remove.h index 6019bfa16..640e94ea3 100644 --- a/src/cli/Remove.h +++ b/src/cli/Remove.h @@ -25,7 +25,7 @@ class Remove : public DatabaseCommand public: Remove(); - int executeWithDatabase(QSharedPointer db, QSharedPointer parser); + int executeWithDatabase(QSharedPointer db, QSharedPointer parser) override; }; #endif // KEEPASSXC_REMOVE_H diff --git a/src/cli/RemoveGroup.cpp b/src/cli/RemoveGroup.cpp index 6455af496..43446a0e7 100644 --- a/src/cli/RemoveGroup.cpp +++ b/src/cli/RemoveGroup.cpp @@ -18,6 +18,7 @@ #include "RemoveGroup.h" #include "Utils.h" +#include "core/Global.h" #include "core/Group.h" #include "core/Metadata.h" @@ -30,9 +31,7 @@ RemoveGroup::RemoveGroup() positionalArguments.append({QString("group"), QObject::tr("Path of the group to remove."), QString("")}); } -RemoveGroup::~RemoveGroup() -{ -} +RemoveGroup::~RemoveGroup() = default; int RemoveGroup::executeWithDatabase(QSharedPointer database, QSharedPointer parser) { @@ -44,12 +43,12 @@ int RemoveGroup::executeWithDatabase(QSharedPointer database, QSharedP // Recursive option means were looking for a group to remove. QPointer group = database->rootGroup()->findGroupByPath(groupPath); if (!group) { - err << QObject::tr("Group %1 not found.").arg(groupPath) << endl; + err << QObject::tr("Group %1 not found.").arg(groupPath) << Qt::endl; return EXIT_FAILURE; } if (group == database->rootGroup()) { - err << QObject::tr("Cannot remove root group from database.") << endl; + err << QObject::tr("Cannot remove root group from database.") << Qt::endl; return EXIT_FAILURE; } @@ -64,14 +63,14 @@ int RemoveGroup::executeWithDatabase(QSharedPointer database, QSharedP QString errorMessage; if (!database->save(Database::Atomic, {}, &errorMessage)) { - err << QObject::tr("Unable to save database to file: %1").arg(errorMessage) << endl; + err << QObject::tr("Unable to save database to file: %1").arg(errorMessage) << Qt::endl; return EXIT_FAILURE; } if (recycled) { - out << QObject::tr("Successfully recycled group %1.").arg(groupPath) << endl; + out << QObject::tr("Successfully recycled group %1.").arg(groupPath) << Qt::endl; } else { - out << QObject::tr("Successfully deleted group %1.").arg(groupPath) << endl; + out << QObject::tr("Successfully deleted group %1.").arg(groupPath) << Qt::endl; } return EXIT_SUCCESS; diff --git a/src/cli/RemoveGroup.h b/src/cli/RemoveGroup.h index 2b5194665..20518a005 100644 --- a/src/cli/RemoveGroup.h +++ b/src/cli/RemoveGroup.h @@ -24,9 +24,9 @@ class RemoveGroup : public DatabaseCommand { public: RemoveGroup(); - ~RemoveGroup(); + ~RemoveGroup() override; - int executeWithDatabase(QSharedPointer db, QSharedPointer parser); + int executeWithDatabase(QSharedPointer db, QSharedPointer parser) override; }; #endif // KEEPASSXC_REMOVEGROUP_H diff --git a/src/cli/Search.cpp b/src/cli/Search.cpp index 44f1743e3..fcaeadd6a 100644 --- a/src/cli/Search.cpp +++ b/src/cli/Search.cpp @@ -21,6 +21,7 @@ #include "Utils.h" #include "core/EntrySearcher.h" +#include "core/Global.h" #include "core/Group.h" Search::Search() @@ -40,12 +41,12 @@ int Search::executeWithDatabase(QSharedPointer database, QSharedPointe EntrySearcher searcher; auto results = searcher.search(args.at(1), database->rootGroup(), true); if (results.isEmpty()) { - err << "No results for that search term." << endl; + err << "No results for that search term." << Qt::endl; return EXIT_FAILURE; } for (const Entry* result : asConst(results)) { - out << result->path().prepend('/') << endl; + out << result->path().prepend('/') << Qt::endl; } return EXIT_SUCCESS; } diff --git a/src/cli/Show.cpp b/src/cli/Show.cpp index c8cb430ed..a65809a16 100644 --- a/src/cli/Show.cpp +++ b/src/cli/Show.cpp @@ -23,13 +23,11 @@ #include -const QCommandLineOption Show::TotpOption = QCommandLineOption(QStringList() << "t" - << "totp", - QObject::tr("Show the entry's current TOTP.")); +const QCommandLineOption Show::TotpOption = + QCommandLineOption(QStringList() << "t" << "totp", QObject::tr("Show the entry's current TOTP.")); const QCommandLineOption Show::ProtectedAttributesOption = - QCommandLineOption(QStringList() << "s" - << "show-protected", + QCommandLineOption(QStringList() << "s" << "show-protected", QObject::tr("Show the protected attributes in clear text.")); const QCommandLineOption Show::AllAttributesOption = @@ -39,8 +37,7 @@ const QCommandLineOption Show::AttachmentsOption = QCommandLineOption(QStringList() << "show-attachments", QObject::tr("Show the attachments of the entry.")); const QCommandLineOption Show::AttributesOption = QCommandLineOption( - QStringList() << "a" - << "attributes", + QStringList() << "a" << "attributes", QObject::tr( "Names of the attributes to show. " "This option can be specified more than once, with each attribute shown one-per-line in the given order. " @@ -73,12 +70,12 @@ int Show::executeWithDatabase(QSharedPointer database, QSharedPointer< Entry* entry = database->rootGroup()->findEntryByPath(entryPath); if (!entry) { - err << QObject::tr("Could not find entry with path %1.").arg(entryPath) << endl; + err << QObject::tr("Could not find entry with path %1.").arg(entryPath) << Qt::endl; return EXIT_FAILURE; } if (showTotp && !entry->hasTotp()) { - err << QObject::tr("Entry with path %1 has no TOTP set up.").arg(entryPath) << endl; + err << QObject::tr("Entry with path %1 has no TOTP set up.").arg(entryPath) << Qt::endl; return EXIT_FAILURE; } @@ -113,20 +110,20 @@ int Show::executeWithDatabase(QSharedPointer database, QSharedPointer< if (!attributesWereSpecified) { out << attributeName << ": "; } - out << Utils::getTopLevelField(entry, attributeName) << endl; + out << Utils::getTopLevelField(entry, attributeName) << Qt::endl; continue; } QStringList attrs = Utils::findAttributes(*entry->attributes(), attributeName); if (attrs.isEmpty()) { encounteredError = true; - err << QObject::tr("ERROR: unknown attribute %1.").arg(attributeName) << endl; + err << QObject::tr("ERROR: unknown attribute %1.").arg(attributeName) << Qt::endl; continue; } else if (attrs.size() > 1) { encounteredError = true; err << QObject::tr("ERROR: attribute %1 is ambiguous, it matches %2.") .arg(attributeName, QLocale().createSeparatedList(attrs)) - << endl; + << Qt::endl; continue; } QString canonicalName = attrs[0]; @@ -134,33 +131,33 @@ int Show::executeWithDatabase(QSharedPointer database, QSharedPointer< out << canonicalName << ": "; } if (entry->attributes()->isProtected(canonicalName) && !attributesWereSpecified && !showProtectedAttributes) { - out << "PROTECTED" << endl; + out << "PROTECTED" << Qt::endl; } else { - out << entry->resolveMultiplePlaceholders(entry->attributes()->value(canonicalName)) << endl; + out << entry->resolveMultiplePlaceholders(entry->attributes()->value(canonicalName)) << Qt::endl; } } if (parser->isSet(Show::AttachmentsOption)) { // Separate attachment output from attributes output via a newline. - out << endl; + out << Qt::endl; EntryAttachments* attachments = entry->attachments(); if (attachments->isEmpty()) { - out << QObject::tr("No attachments present.") << endl; + out << QObject::tr("No attachments present.") << Qt::endl; } else { - out << QObject::tr("Attachments:") << endl; + out << QObject::tr("Attachments:") << Qt::endl; // Iterate over the attachments and output their names and size line-by-line, indented. for (const QString& attachmentName : attachments->keys()) { // TODO: use QLocale::formattedDataSize when >= Qt 5.10 QString attachmentSize = Tools::humanReadableFileSize(attachments->value(attachmentName).size(), 1); - out << " " << attachmentName << " (" << attachmentSize << ")" << endl; + out << " " << attachmentName << " (" << attachmentSize << ")" << Qt::endl; } } } if (showTotp) { - out << entry->totp() << endl; + out << entry->totp() << Qt::endl; } return encounteredError ? EXIT_FAILURE : EXIT_SUCCESS; diff --git a/src/cli/Show.h b/src/cli/Show.h index 8af32937e..ca00a815f 100644 --- a/src/cli/Show.h +++ b/src/cli/Show.h @@ -25,7 +25,7 @@ class Show : public DatabaseCommand public: Show(); - int executeWithDatabase(QSharedPointer db, QSharedPointer parser); + int executeWithDatabase(QSharedPointer db, QSharedPointer parser) override; static const QCommandLineOption TotpOption; static const QCommandLineOption AllAttributesOption; diff --git a/src/cli/Utils.cpp b/src/cli/Utils.cpp index d8134de26..ae4874c43 100644 --- a/src/cli/Utils.cpp +++ b/src/cli/Utils.cpp @@ -20,6 +20,7 @@ #include "core/Database.h" #include "core/Entry.h" #include "core/EntryAttributes.h" +#include "core/Global.h" #include "keys/FileKey.h" #ifdef WITH_XC_YUBIKEY #include "keys/ChallengeResponseKey.h" @@ -42,6 +43,11 @@ namespace Utils QTextStream STDIN; QTextStream DEVNULL; +#ifdef Q_OS_WIN + UINT origCodePage; + UINT origOutputCodePage; +#endif + void setDefaultTextStreams() { auto fd = new QFile(); @@ -65,6 +71,9 @@ namespace Utils DEVNULL.setDevice(fd); #ifdef Q_OS_WIN + origCodePage = GetConsoleCP(); + origOutputCodePage = GetConsoleOutputCP(); + // On Windows, we ask via keepassxc-cli.exe.manifest to use UTF-8, // but the console code-page isn't automatically changed to match. SetConsoleCP(GetACP()); @@ -72,6 +81,14 @@ namespace Utils #endif } + void resetTextStreams() + { +#ifdef Q_OS_WIN + SetConsoleCP(origCodePage); + SetConsoleOutputCP(origOutputCodePage); +#endif + } + void setStdinEcho(bool enable = true) { #ifdef Q_OS_WIN @@ -111,22 +128,22 @@ namespace Utils QFileInfo dbFileInfo(databaseFilename); if (dbFileInfo.canonicalFilePath().isEmpty()) { - err << QObject::tr("Failed to open database file %1: not found").arg(databaseFilename) << endl; + err << QObject::tr("Failed to open database file %1: not found").arg(databaseFilename) << Qt::endl; return {}; } if (!dbFileInfo.isFile()) { - err << QObject::tr("Failed to open database file %1: not a plain file").arg(databaseFilename) << endl; + err << QObject::tr("Failed to open database file %1: not a plain file").arg(databaseFilename) << Qt::endl; return {}; } if (!dbFileInfo.isReadable()) { - err << QObject::tr("Failed to open database file %1: not readable").arg(databaseFilename) << endl; + err << QObject::tr("Failed to open database file %1: not readable").arg(databaseFilename) << Qt::endl; return {}; } if (isPasswordProtected) { - err << QObject::tr("Enter password to unlock %1: ").arg(databaseFilename) << flush; + err << QObject::tr("Enter password to unlock %1: ").arg(databaseFilename) << Qt::flush; QString line = Utils::getPassword(quiet); auto passwordKey = QSharedPointer::create(); passwordKey->setPassword(line); @@ -138,7 +155,7 @@ namespace Utils QString errorMessage; // LCOV_EXCL_START if (!fileKey->load(keyFilename, &errorMessage)) { - err << QObject::tr("Failed to load key file %1: %2").arg(keyFilename, errorMessage) << endl; + err << QObject::tr("Failed to load key file %1: %2").arg(keyFilename, errorMessage) << Qt::endl; return {}; } @@ -146,7 +163,7 @@ namespace Utils err << QObject::tr("WARNING: You are using an old key file format which KeePassXC may\n" "stop supporting in the future.\n\n" "Please consider generating a new key file.") - << endl; + << Qt::endl; } // LCOV_EXCL_STOP @@ -163,20 +180,20 @@ namespace Utils slot = parts[0].toInt(&ok); if (!ok || (slot != 1 && slot != 2)) { - err << QObject::tr("Invalid YubiKey slot %1").arg(parts[0]) << endl; + err << QObject::tr("Invalid YubiKey slot %1").arg(parts[0]) << Qt::endl; return {}; } if (parts.size() > 1) { serial = parts[1].toUInt(&ok, 10); if (!ok) { - err << QObject::tr("Invalid YubiKey serial %1").arg(parts[1]) << endl; + err << QObject::tr("Invalid YubiKey serial %1").arg(parts[1]) << Qt::endl; return {}; } } QObject::connect(YubiKey::instance(), &YubiKey::userInteractionRequest, [&] { - err << QObject::tr("Please present or touch your YubiKey to continue.") << "\n\n" << flush; + err << QObject::tr("Please present or touch your YubiKey to continue.") << "\n\n" << Qt::flush; }); auto key = QSharedPointer(new ChallengeResponseKey({serial, slot})); @@ -193,7 +210,7 @@ namespace Utils if (db->open(databaseFilename, compositeKey, &error)) { return db; } else { - err << error << endl; + err << error << Qt::endl; return {}; } } @@ -209,7 +226,7 @@ namespace Utils #ifdef __AFL_COMPILER // Fuzz test build takes password from environment variable to // allow non-interactive operation - const auto env = getenv("KEYPASSXC_AFL_PASSWORD"); + const auto env = getenv("KEEPASSXC_AFL_PASSWORD"); return env ? env : ""; #else auto& in = STDIN; @@ -218,7 +235,7 @@ namespace Utils setStdinEcho(false); QString line = in.readLine(); setStdinEcho(true); - out << endl; + out << Qt::endl; return line; #endif // __AFL_COMPILER @@ -248,7 +265,7 @@ namespace Utils if (ans.toLower().startsWith("y")) { passwordKey = QSharedPointer::create(""); } - err << endl; + err << Qt::endl; } else { err << QObject::tr("Repeat password: "); err.flush(); @@ -257,7 +274,7 @@ namespace Utils if (password == repeat) { passwordKey = QSharedPointer::create(password); } else { - err << QObject::tr("Error: Passwords do not match.") << endl; + err << QObject::tr("Error: Passwords do not match.") << Qt::endl; } } @@ -303,7 +320,7 @@ namespace Utils QScopedPointer clipProcess(new QProcess(nullptr)); // Skip empty parts, otherwise the program may clip the empty string - QStringList progArgs = prog.second.split(" ", QString::SkipEmptyParts); + QStringList progArgs = prog.second.split(" ", Qt::SkipEmptyParts); clipProcess->start(prog.first, progArgs); clipProcess->waitForStarted(); @@ -329,6 +346,8 @@ namespace Utils if (clipProcess->exitCode() == EXIT_SUCCESS) { return EXIT_SUCCESS; + } else { + failedProgramNames.append(prog.first); } } @@ -384,7 +403,7 @@ namespace Utils if (fieldName == TagsFieldName) { return entry->tags(); } - return QString(""); + return ""; } QStringList findAttributes(const EntryAttributes& attributes, const QString& name) @@ -413,7 +432,7 @@ namespace Utils * * @param path Path to the key file to be loaded * @param fileKey Resulting fileKey - * @return true if the key file was loaded succesfully + * @return true if the key file was loaded successfully */ bool loadFileKey(const QString& path, QSharedPointer& fileKey) { @@ -425,13 +444,13 @@ namespace Utils fileKey->create(path, &error); if (!error.isEmpty()) { - err << QObject::tr("Creating KeyFile %1 failed: %2").arg(path, error) << endl; + err << QObject::tr("Creating KeyFile %1 failed: %2").arg(path, error) << Qt::endl; return false; } } if (!fileKey->load(path, &error)) { - err << QObject::tr("Loading KeyFile %1 failed: %2").arg(path, error) << endl; + err << QObject::tr("Loading KeyFile %1 failed: %2").arg(path, error) << Qt::endl; return false; } diff --git a/src/cli/Utils.h b/src/cli/Utils.h index 84ddbbb4b..6a272fc62 100644 --- a/src/cli/Utils.h +++ b/src/cli/Utils.h @@ -39,6 +39,7 @@ namespace Utils static const QStringList EntryFieldNames(QStringList() << UuidFieldName << TagsFieldName); void setDefaultTextStreams(); + void resetTextStreams(); void setStdinEcho(bool enable); bool loadFileKey(const QString& path, QSharedPointer& fileKey); diff --git a/src/cli/keepassxc-cli.cpp b/src/cli/keepassxc-cli.cpp index abf1b0efd..2c4bd1aa2 100644 --- a/src/cli/keepassxc-cli.cpp +++ b/src/cli/keepassxc-cli.cpp @@ -154,7 +154,7 @@ int enterInteractiveMode(const QStringList& arguments) auto cmd = Commands::getCommand(args[0]); if (!cmd) { - err << QObject::tr("Unknown command %1").arg(args[0]) << endl; + err << QObject::tr("Unknown command %1").arg(args[0]) << Qt::endl; continue; } else if (cmd->name == "quit" || cmd->name == "exit") { break; @@ -181,6 +181,8 @@ int main(int argc, char** argv) QCoreApplication app(argc, argv); QCoreApplication::setApplicationVersion(KEEPASSXC_VERSION); + // Cleanup code pages after cli exits + QObject::connect(&app, &QCoreApplication::destroyed, &app, [] { Utils::resetTextStreams(); }); Bootstrap::bootstrap(config()->get(Config::GUI_Language).toString()); Utils::setDefaultTextStreams(); @@ -216,11 +218,13 @@ int main(int argc, char** argv) if (parser.positionalArguments().empty()) { if (parser.isSet("version")) { // Switch to parser.showVersion() when available (QT 5.4). - out << KEEPASSXC_VERSION << endl; + out << KEEPASSXC_VERSION << Qt::endl; return EXIT_SUCCESS; - } else if (parser.isSet(debugInfoOption)) { + } + + if (parser.isSet(debugInfoOption)) { QString debugInfo = Tools::debugInfo().append("\n").append(Crypto::debugInfo()); - out << debugInfo << endl; + out << debugInfo << Qt::endl; return EXIT_SUCCESS; } // showHelp exits the application immediately. @@ -234,7 +238,7 @@ int main(int argc, char** argv) auto command = Commands::getCommand(commandName); if (!command) { - err << QObject::tr("Invalid command %1.").arg(commandName) << endl; + err << QObject::tr("Invalid command %1.").arg(commandName) << Qt::endl; err << parser.helpText(); return EXIT_FAILURE; } diff --git a/src/core/Alloc.cpp b/src/core/Alloc.cpp index 38ee8c182..f9ec317cc 100644 --- a/src/core/Alloc.cpp +++ b/src/core/Alloc.cpp @@ -25,7 +25,7 @@ #elif defined(HAVE_MALLOC_H) #include #else -#include +#include #endif #if defined(NDEBUG) && !defined(__cpp_sized_deallocation) diff --git a/src/core/AsyncTask.h b/src/core/AsyncTask.h index c12360231..da7734c27 100644 --- a/src/core/AsyncTask.h +++ b/src/core/AsyncTask.h @@ -61,7 +61,7 @@ namespace AsyncTask * * @param task std::function object to run * @param context QObject responsible for calling this function - * @param callback std::function object to run after the task completess + * @param callback std::function object to run after the task completes */ template void runThenCallback(FunctionObject task, QObject* context, FunctionObject2 callback) diff --git a/src/core/Base32.cpp b/src/core/Base32.cpp index 05841121a..d0a148eec 100644 --- a/src/core/Base32.cpp +++ b/src/core/Base32.cpp @@ -50,7 +50,7 @@ QVariant Base32::decode(const QByteArray& encodedData) } if (encodedData.size() % 8 != 0) { - return QVariant(); + return {}; } int nPads = 0; @@ -119,7 +119,7 @@ QVariant Base32::decode(const QByteArray& encodedData) continue; } else { // illegal character - return QVariant(); + return {}; } } } @@ -145,7 +145,7 @@ QVariant Base32::decode(const QByteArray& encodedData) QByteArray Base32::encode(const QByteArray& data) { if (data.size() < 1) { - return QByteArray(); + return {}; } const int nBits = data.size() * 8; diff --git a/src/core/Bootstrap.cpp b/src/core/Bootstrap.cpp index 739e3446f..061cba136 100644 --- a/src/core/Bootstrap.cpp +++ b/src/core/Bootstrap.cpp @@ -167,7 +167,7 @@ namespace Bootstrap goto Cleanup; } - // Retrieve CreaterOwnerRights SID + // Retrieve CreatorOwnerRights SID pOwnerRightsSid = static_cast(HeapAlloc(GetProcessHeap(), 0, pOwnerRightsSidSize)); if (pOwnerRightsSid == nullptr) { goto Cleanup; @@ -180,7 +180,8 @@ namespace Bootstrap // Calculate the amount of memory that must be allocated for the DACL cbACL = sizeof(ACL) + sizeof(ACCESS_ALLOWED_ACE) + GetLengthSid(pTokenUser->User.Sid) - + sizeof(ACCESS_ALLOWED_ACE) + GetLengthSid(pLocalSystemSid) + GetLengthSid(pOwnerRightsSid); + + sizeof(ACCESS_ALLOWED_ACE) + GetLengthSid(pLocalSystemSid) + sizeof(ACCESS_ALLOWED_ACE) + + GetLengthSid(pOwnerRightsSid); // Create and initialize an ACL pACL = static_cast(HeapAlloc(GetProcessHeap(), 0, cbACL)); diff --git a/src/core/Clock.cpp b/src/core/Clock.cpp index 5704d4bff..f501daee7 100644 --- a/src/core/Clock.cpp +++ b/src/core/Clock.cpp @@ -16,6 +16,8 @@ */ #include "Clock.h" +#include + QSharedPointer Clock::m_instance; QDateTime Clock::currentDateTimeUtc() @@ -50,12 +52,12 @@ QDateTime Clock::serialized(const QDateTime& dateTime) QDateTime Clock::datetimeUtc(int year, int month, int day, int hour, int min, int second) { - return QDateTime(QDate(year, month, day), QTime(hour, min, second), Qt::UTC); + return {QDate(year, month, day), QTime(hour, min, second), Qt::UTC}; } QDateTime Clock::datetime(int year, int month, int day, int hour, int min, int second) { - return QDateTime(QDate(year, month, day), QTime(hour, min, second), Qt::LocalTime); + return {QDate(year, month, day), QTime(hour, min, second), Qt::LocalTime}; } QDateTime Clock::datetimeUtc(qint64 msecSinceEpoch) @@ -78,13 +80,15 @@ QDateTime Clock::parse(const QString& text, const QString& format) return QDateTime::fromString(text, format); } -Clock::~Clock() +QString Clock::toString(const QDateTime& dateTime) { + static QLocale locale; + return locale.toString(dateTime, QLocale::ShortFormat); } -Clock::Clock() -{ -} +Clock::~Clock() = default; + +Clock::Clock() = default; QDateTime Clock::currentDateTimeUtcImpl() const { diff --git a/src/core/Clock.h b/src/core/Clock.h index 4d1ee2537..ca2577e91 100644 --- a/src/core/Clock.h +++ b/src/core/Clock.h @@ -41,6 +41,8 @@ public: static QDateTime parse(const QString& text, Qt::DateFormat format = Qt::TextDate); static QDateTime parse(const QString& text, const QString& format); + static QString toString(const QDateTime& dateTime); + virtual ~Clock(); protected: diff --git a/src/core/Config.cpp b/src/core/Config.cpp index ed570cdd9..f1a78830d 100644 --- a/src/core/Config.cpp +++ b/src/core/Config.cpp @@ -66,6 +66,7 @@ static const QHash configStrings = { {Config::UseDirectWriteSaves,{QS("UseDirectWriteSaves"), Local, false}}, {Config::SearchLimitGroup,{QS("SearchLimitGroup"), Roaming, false}}, {Config::MinimizeOnOpenUrl,{QS("MinimizeOnOpenUrl"), Roaming, false}}, + {Config::OpenURLOnDoubleClick, {QS("OpenURLOnDoubleClick"), Roaming, true}}, {Config::HideWindowOnCopy,{QS("HideWindowOnCopy"), Roaming, false}}, {Config::MinimizeOnCopy,{QS("MinimizeOnCopy"), Roaming, true}}, {Config::MinimizeAfterUnlock,{QS("MinimizeAfterUnlock"), Roaming, false}}, @@ -76,6 +77,8 @@ static const QHash configStrings = { {Config::AutoTypeDelay,{QS("AutoTypeDelay"), Roaming, 25}}, {Config::AutoTypeStartDelay,{QS("AutoTypeStartDelay"), Roaming, 500}}, {Config::AutoTypeHideExpiredEntry,{QS("AutoTypeHideExpiredEntry"), Roaming, false}}, + {Config::AutoTypeDialogSortColumn,{QS("AutoTypeDialogSortColumn"), Roaming, 0}}, + {Config::AutoTypeDialogSortOrder,{QS("AutoTypeDialogSortOrder"), Roaming, Qt::AscendingOrder}}, {Config::GlobalAutoTypeKey,{QS("GlobalAutoTypeKey"), Roaming, 0}}, {Config::GlobalAutoTypeModifiers,{QS("GlobalAutoTypeModifiers"), Roaming, 0}}, {Config::GlobalAutoTypeRetypeTime,{QS("GlobalAutoTypeRetypeTime"), Roaming, 15}}, @@ -95,12 +98,11 @@ static const QHash configStrings = { {Config::GUI_HideMenubar, {QS("GUI/HideMenubar"), Roaming, false}}, {Config::GUI_HideToolbar, {QS("GUI/HideToolbar"), Roaming, false}}, {Config::GUI_MovableToolbar, {QS("GUI/MovableToolbar"), Roaming, false}}, + {Config::GUI_HideGroupPanel, {QS("GUI/HideGroupPanel"), Roaming, false}}, {Config::GUI_HidePreviewPanel, {QS("GUI/HidePreviewPanel"), Roaming, false}}, {Config::GUI_AlwaysOnTop, {QS("GUI/GUI_AlwaysOnTop"), Local, false}}, {Config::GUI_ToolButtonStyle, {QS("GUI/ToolButtonStyle"), Roaming, Qt::ToolButtonIconOnly}}, -#ifdef KEEPASSXC_DIST_FLATPAK {Config::GUI_LaunchAtStartup, {QS("GUI/LaunchAtStartup"), Roaming, false}}, -#endif {Config::GUI_ShowTrayIcon, {QS("GUI/ShowTrayIcon"), Roaming, false}}, {Config::GUI_TrayIconAppearance, {QS("GUI/TrayIconAppearance"), Roaming, {}}}, {Config::GUI_MinimizeToTray, {QS("GUI/MinimizeToTray"), Roaming, false}}, @@ -117,6 +119,7 @@ static const QHash configStrings = { {Config::GUI_CheckForUpdatesIncludeBetas, {QS("GUI/CheckForUpdatesIncludeBetas"), Roaming, false}}, {Config::GUI_ShowExpiredEntriesOnDatabaseUnlock, {QS("GUI/ShowExpiredEntriesOnDatabaseUnlock"), Roaming, true}}, {Config::GUI_ShowExpiredEntriesOnDatabaseUnlockOffsetDays, {QS("GUI/ShowExpiredEntriesOnDatabaseUnlockOffsetDays"), Roaming, 3}}, + {Config::GUI_FontSizeOffset, {QS("GUI/FontSizeOffset"), Local, 0}}, {Config::GUI_MainWindowGeometry, {QS("GUI/MainWindowGeometry"), Local, {}}}, {Config::GUI_MainWindowState, {QS("GUI/MainWindowState"), Local, {}}}, @@ -137,6 +140,7 @@ static const QHash configStrings = { {Config::Security_LockDatabaseIdleSeconds, {QS("Security/LockDatabaseIdleSeconds"), Roaming, 240}}, {Config::Security_LockDatabaseMinimize, {QS("Security/LockDatabaseMinimize"), Roaming, false}}, {Config::Security_LockDatabaseScreenLock, {QS("Security/LockDatabaseScreenLock"), Roaming, true}}, + {Config::Security_LockDatabaseOnUserSwitch, {QS("Security/LockDatabaseOnUserSwitch"), Roaming, true}}, {Config::Security_RelockAutoType, {QS("Security/RelockAutoType"), Roaming, false}}, {Config::Security_PasswordsHidden, {QS("Security/PasswordsHidden"), Roaming, true}}, {Config::Security_PasswordEmptyPlaceholder, {QS("Security/PasswordEmptyPlaceholder"), Roaming, false}}, @@ -159,6 +163,7 @@ static const QHash configStrings = { {Config::Browser_UseCustomProxy, {QS("Browser/UseCustomProxy"), Roaming, false}}, {Config::Browser_CustomProxyLocation, {QS("Browser/CustomProxyLocation"), Roaming, {}}}, {Config::Browser_UpdateBinaryPath, {QS("Browser/UpdateBinaryPath"), Roaming, true}}, + {Config::Browser_AllowGetDatabaseEntriesRequest, {QS("Browser/AllowGetDatabaseEntriesRequest"), Roaming, false}}, {Config::Browser_AllowExpiredCredentials, {QS("Browser/AllowExpiredCredentials"), Roaming, false}}, {Config::Browser_AlwaysAllowAccess, {QS("Browser/AlwaysAllowAccess"), Roaming, false}}, {Config::Browser_AlwaysAllowUpdate, {QS("Browser/AlwaysAllowUpdate"), Roaming, false}}, @@ -220,7 +225,6 @@ static const QHash configStrings = { // Messages {Config::Messages_NoLegacyKeyFileWarning, {QS("Messages/NoLegacyKeyFileWarning"), Roaming, false}}, - {Config::Messages_Qt55CompatibilityWarning, {QS("Messages/Qt55CompatibilityWarning"), Local, false}}, {Config::Messages_HidePreReleaseWarning, {QS("Messages/HidePreReleaseWarning"), Local, {}}}}; // clang-format on @@ -303,6 +307,45 @@ void Config::resetToDefaults() } } +bool Config::importSettings(const QString& fileName) +{ + // Ensure file is valid ini with values + QSettings settings(fileName, QSettings::IniFormat); + if (settings.status() != QSettings::NoError || settings.allKeys().isEmpty()) { + return false; + } + + // Only import valid roaming settings + auto isValidSetting = [](const QString& key) { + for (const auto& value : configStrings.values()) { + if (value.type == ConfigType::Roaming && value.name == key) { + return true; + } + } + return false; + }; + + // Clear existing settings and set valid items + m_settings->clear(); + for (const auto& key : settings.allKeys()) { + if (isValidSetting(key)) { + m_settings->setValue(key, settings.value(key)); + } + } + + sync(); + + return true; +} + +void Config::exportSettings(const QString& fileName) const +{ + QSettings settings(fileName, QSettings::IniFormat); + for (const auto& key : m_settings->allKeys()) { + settings.setValue(key, m_settings->value(key)); + } +} + /** * Map of configuration file settings that are either deprecated, or have * had their name changed to their new config enum values. @@ -361,7 +404,7 @@ static const QHash deprecationMap = { {QS("generator/WordList"), Config::PasswordGenerator_WordList}, {QS("generator/WordCase"), Config::PasswordGenerator_WordCase}, {QS("generator/Type"), Config::PasswordGenerator_Type}, - {QS("QtErrorMessageShown"), Config::Messages_Qt55CompatibilityWarning}, + {QS("QtErrorMessageShown"), Config::Deleted}, {QS("GUI/HidePasswords"), Config::Deleted}, {QS("GUI/DarkTrayIcon"), Config::Deleted}, @@ -374,8 +417,9 @@ static const QHash deprecationMap = { {QS("UseTouchID"), Config::Deleted}, {QS("Security/ResetTouchId"), Config::Deleted}, {QS("Security/ResetTouchIdTimeout"), Config::Deleted}, + {QS("Security/ResetTouchIdScreenlock"), Config::Deleted}, - // 2.7.8 + // 2.8.0 {QS("GUI/AdvancedSettings"), Config::Deleted}, {QS("Security/PasswordsRepeatVisible"), Config::Deleted}}; @@ -462,9 +506,7 @@ Config::Config(QObject* parent) init(configFiles.first, configFiles.second); } -Config::~Config() -{ -} +Config::~Config() = default; void Config::init(const QString& configFileName, const QString& localConfigFileName) { @@ -478,6 +520,28 @@ void Config::init(const QString& configFileName, const QString& localConfigFileN QDir().rmdir(QFileInfo(localConfigFileName).absolutePath()); } +#if defined(Q_OS_LINUX) + // Upgrade from previous KeePassXC version which stores its config + // in ~/.cache on Linux instead of ~/.local/state. + // Move file to correct location before continuing. + if (!QFile::exists(localConfigFileName)) { + QString oldLocalConfigPath = + QStandardPaths::writableLocation(QStandardPaths::GenericCacheLocation) + "/keepassxc"; + QString suffix; +#ifdef QT_DEBUG + suffix = "_debug"; +#endif + oldLocalConfigPath += QString("/keepassxc%1.ini").arg(suffix); + oldLocalConfigPath = QDir::toNativeSeparators(oldLocalConfigPath); + if (QFile::exists(oldLocalConfigPath)) { + QDir().mkpath(QFileInfo(localConfigFileName).absolutePath()); + QFile::copy(oldLocalConfigPath, localConfigFileName); + QFile::remove(oldLocalConfigPath); + QDir().rmdir(QFileInfo(oldLocalConfigPath).absolutePath()); + } + } +#endif + m_settings.reset(new QSettings(configFileName, QSettings::IniFormat)); if (!localConfigFileName.isEmpty() && configFileName != localConfigFileName) { m_localSettings.reset(new QSettings(localConfigFileName, QSettings::IniFormat)); @@ -490,20 +554,8 @@ void Config::init(const QString& configFileName, const QString& localConfigFileN QPair Config::defaultConfigFiles() { // Check if we are running in portable mode, if so store the config files local to the app -#ifdef Q_OS_WIN - // Enable QFileInfo::isWritable check on Windows - extern Q_CORE_EXPORT int qt_ntfs_permission_lookup; - qt_ntfs_permission_lookup++; -#endif - auto portablePath = QCoreApplication::applicationDirPath().append("/%1"); - auto portableFile = portablePath.arg(".portable"); - bool isPortable = QFile::exists(portableFile) && QFileInfo(portableFile).isWritable(); -#ifdef Q_OS_WIN - qt_ntfs_permission_lookup--; -#endif - - if (isPortable) { - return {portablePath.arg("config/keepassxc.ini"), portablePath.arg("config/keepassxc_local.ini")}; + if (isPortable()) { + return {portableConfigDir().append("/keepassxc.ini"), portableConfigDir().append("/keepassxc_local.ini")}; } QString configPath; @@ -518,7 +570,16 @@ QPair Config::defaultConfigFiles() #else // On case-sensitive Operating Systems, force use of lowercase app directories configPath = QStandardPaths::writableLocation(QStandardPaths::GenericConfigLocation) + "/keepassxc"; - localConfigPath = QStandardPaths::writableLocation(QStandardPaths::GenericCacheLocation) + "/keepassxc"; + // Qt does not support XDG_STATE_HOME yet, change this once XDG_STATE_HOME is added + QString xdgStateHome = QFile::decodeName(qgetenv("XDG_STATE_HOME")); + if (!xdgStateHome.startsWith(u'/')) { + xdgStateHome.clear(); // spec says relative paths should be ignored + } + if (xdgStateHome.isEmpty()) { + xdgStateHome = QDir::homePath() + "/.local/state"; + } + + localConfigPath = xdgStateHome + "/keepassxc"; #endif QString suffix; @@ -558,17 +619,49 @@ void Config::createConfigFromFile(const QString& configFileName, const QString& qApp); } -void Config::createTempFileInstance() +bool Config::isPortable() { - if (m_instance) { - delete m_instance; +#ifdef Q_OS_WIN + // Enable QFileInfo::isWritable check on Windows + extern Q_CORE_EXPORT int qt_ntfs_permission_lookup; + qt_ntfs_permission_lookup++; +#endif + auto portablePath = QCoreApplication::applicationDirPath().append("/%1"); + auto portableFile = portablePath.arg(".portable"); + auto isPortable = QFile::exists(portableFile) && QFileInfo(portableFile).isWritable(); +#ifdef Q_OS_WIN + qt_ntfs_permission_lookup--; +#endif + return isPortable; +} + +QString Config::portableConfigDir() +{ + return QCoreApplication::applicationDirPath().append("/config"); +} + +QList Config::getShortcuts() const +{ + m_settings->beginGroup("Shortcuts"); + const auto keys = m_settings->childKeys(); + QList ret; + ret.reserve(keys.size()); + for (const auto& key : keys) { + const auto shortcut = m_settings->value(key).toString(); + ret.push_back(ShortcutEntry{key, shortcut}); } - auto* tmpFile = new QTemporaryFile(); - bool openResult = tmpFile->open(); - Q_ASSERT(openResult); - Q_UNUSED(openResult); - m_instance = new Config(tmpFile->fileName(), "", qApp); - tmpFile->setParent(m_instance); + m_settings->endGroup(); + return ret; +} + +void Config::setShortcuts(const QList& shortcuts) +{ + m_settings->beginGroup("Shortcuts"); + m_settings->remove(""); // clear previous + for (const auto& shortcutEntry : shortcuts) { + m_settings->setValue(shortcutEntry.name, shortcutEntry.shortcut); + } + m_settings->endGroup(); } #undef QS diff --git a/src/core/Config.h b/src/core/Config.h index 9624a1a84..5678bbc6e 100644 --- a/src/core/Config.h +++ b/src/core/Config.h @@ -21,6 +21,7 @@ #include #include +#include class QSettings; @@ -48,6 +49,7 @@ public: UseDirectWriteSaves, SearchLimitGroup, MinimizeOnOpenUrl, + OpenURLOnDoubleClick, HideWindowOnCopy, MinimizeOnCopy, MinimizeAfterUnlock, @@ -58,6 +60,8 @@ public: AutoTypeDelay, AutoTypeStartDelay, AutoTypeHideExpiredEntry, + AutoTypeDialogSortColumn, + AutoTypeDialogSortOrder, GlobalAutoTypeKey, GlobalAutoTypeModifiers, GlobalAutoTypeRetypeTime, @@ -76,12 +80,11 @@ public: GUI_HideMenubar, GUI_HideToolbar, GUI_MovableToolbar, + GUI_HideGroupPanel, GUI_HidePreviewPanel, GUI_AlwaysOnTop, GUI_ToolButtonStyle, -#ifdef KEEPASSXC_DIST_FLATPAK GUI_LaunchAtStartup, -#endif GUI_ShowTrayIcon, GUI_TrayIconAppearance, GUI_MinimizeToTray, @@ -95,8 +98,10 @@ public: GUI_CompactMode, GUI_CheckForUpdates, GUI_CheckForUpdatesIncludeBetas, + SearchWaitForEnter, GUI_ShowExpiredEntriesOnDatabaseUnlock, GUI_ShowExpiredEntriesOnDatabaseUnlockOffsetDays, + GUI_FontSizeOffset, GUI_MainWindowGeometry, GUI_MainWindowState, @@ -117,6 +122,7 @@ public: Security_LockDatabaseIdleSeconds, Security_LockDatabaseMinimize, Security_LockDatabaseScreenLock, + Security_LockDatabaseOnUserSwitch, Security_RelockAutoType, Security_PasswordsHidden, Security_PasswordEmptyPlaceholder, @@ -138,6 +144,7 @@ public: Browser_UseCustomProxy, Browser_CustomProxyLocation, Browser_UpdateBinaryPath, + Browser_AllowGetDatabaseEntriesRequest, Browser_AllowExpiredCredentials, Browser_AlwaysAllowAccess, Browser_AlwaysAllowUpdate, @@ -194,13 +201,18 @@ public: PasswordGenerator_Type, Messages_NoLegacyKeyFileWarning, - Messages_Qt55CompatibilityWarning, Messages_HidePreReleaseWarning, // Special internal value Deleted }; + struct ShortcutEntry + { + QString name; + QString shortcut; + }; + ~Config() override; QVariant get(ConfigKey key); QVariant getDefault(ConfigKey key); @@ -211,9 +223,16 @@ public: void sync(); void resetToDefaults(); + bool importSettings(const QString& fileName); + void exportSettings(const QString& fileName) const; + + QList getShortcuts() const; + void setShortcuts(const QList& shortcuts); + static Config* instance(); static void createConfigFromFile(const QString& configFileName, const QString& localConfigFileName = {}); - static void createTempFileInstance(); + static bool isPortable(); + static QString portableConfigDir(); signals: void changed(ConfigKey key); diff --git a/src/core/CustomData.cpp b/src/core/CustomData.cpp index 354dbf7d6..3c734e65f 100644 --- a/src/core/CustomData.cpp +++ b/src/core/CustomData.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2018 KeePassXC Team + * Copyright (C) 2024 KeePassXC Team * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -21,12 +21,12 @@ #include "core/Global.h" const QString CustomData::LastModified = QStringLiteral("_LAST_MODIFIED"); -const QString CustomData::Created = QStringLiteral("_CREATED"); +const QString CustomData::Created = QStringLiteral("_CREATED_"); const QString CustomData::BrowserKeyPrefix = QStringLiteral("KPXC_BROWSER_"); -const QString CustomData::BrowserLegacyKeyPrefix = QStringLiteral("Public Key: "); const QString CustomData::ExcludeFromReportsLegacy = QStringLiteral("KnownBad"); const QString CustomData::FdoSecretsExposedGroup = QStringLiteral("FDO_SECRETS_EXPOSED_GROUP"); const QString CustomData::RandomSlug = QStringLiteral("KPXC_RANDOM_SLUG"); +const QString CustomData::RemoteProgramSettings = QStringLiteral("KPXC_REMOTE_SYNC_SETTINGS"); // Fallback item for return by reference static const CustomData::CustomDataItem NULL_ITEM{}; @@ -51,6 +51,15 @@ QString CustomData::value(const QString& key) const return m_data.value(key).value; } +QString CustomData::getKeyWithPrefix(const QString& prefix, const QString& key) +{ + QString keyWithPrefix; + keyWithPrefix.reserve(prefix.length() + key.length()); + keyWithPrefix.append(prefix); + keyWithPrefix.append(key); + return keyWithPrefix; +} + const CustomData::CustomDataItem& CustomData::item(const QString& key) const { auto item = m_data.find(key); @@ -190,7 +199,8 @@ void CustomData::updateLastModified(QDateTime lastModified) bool CustomData::isProtected(const QString& key) const { - return key.startsWith(BrowserKeyPrefix) || key == Created || key == FdoSecretsExposedGroup; + return key.startsWith(BrowserKeyPrefix) || key == Created || key == FdoSecretsExposedGroup + || key == CustomData::RemoteProgramSettings; } bool CustomData::isAutoGenerated(const QString& key) const diff --git a/src/core/CustomData.h b/src/core/CustomData.h index a8ad04487..3ee4d05ef 100644 --- a/src/core/CustomData.h +++ b/src/core/CustomData.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2018 KeePassXC Team + * Copyright (C) 2024 KeePassXC Team * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -64,13 +64,15 @@ public: bool operator==(const CustomData& other) const; bool operator!=(const CustomData& other) const; + static QString getKeyWithPrefix(const QString& prefix, const QString& key); + // Pre-defined keys static const QString LastModified; static const QString Created; static const QString BrowserKeyPrefix; - static const QString BrowserLegacyKeyPrefix; static const QString FdoSecretsExposedGroup; static const QString RandomSlug; + static const QString RemoteProgramSettings; // Pre-KDBX 4.1 static const QString ExcludeFromReportsLegacy; diff --git a/src/core/Database.cpp b/src/core/Database.cpp index d66552172..95f4f1e15 100644 --- a/src/core/Database.cpp +++ b/src/core/Database.cpp @@ -25,6 +25,7 @@ #include "format/KdbxXmlReader.h" #include "format/KeePass2Reader.h" #include "format/KeePass2Writer.h" +#include "streams/HashingStream.h" #include #include @@ -62,8 +63,8 @@ Database::Database() updateTagList(); }); connect(this, &Database::modified, this, [this] { updateTagList(); }); - connect(this, &Database::databaseSaved, this, [this]() { updateCommonUsernames(); }); - connect(m_fileWatcher, &FileWatcher::fileChanged, this, &Database::databaseFileChanged); + connect(this, &Database::databaseSaved, this, [this] { updateCommonUsernames(); }); + connect(m_fileWatcher, &FileWatcher::fileChanged, this, [this] { emit databaseFileChanged(false); }); // static uuid map s_uuidMap.insert(m_uuid, this); @@ -106,10 +107,6 @@ QUuid Database::uuid() const */ bool Database::open(QSharedPointer key, QString* error) { - Q_ASSERT(!m_data.filePath.isEmpty()); - if (m_data.filePath.isEmpty()) { - return false; - } return open(m_data.filePath, std::move(key), error); } @@ -118,6 +115,8 @@ bool Database::open(QSharedPointer key, QString* error) * Unless `readOnly` is set to false, the database will be opened in * read-write mode and fall back to read-only if that is not possible. * + * If key is provided as null, only headers will be read. + * * @param filePath path to the file * @param key composite key for unlocking the database * @param error error message in case of failure @@ -125,6 +124,13 @@ bool Database::open(QSharedPointer key, QString* error) */ bool Database::open(const QString& filePath, QSharedPointer key, QString* error) { + if (filePath.isEmpty()) { + if (error) { + *error = tr("No file path was provided."); + } + return false; + } + QFile dbFile(filePath); if (!dbFile.exists()) { if (error) { @@ -149,6 +155,20 @@ bool Database::open(const QString& filePath, QSharedPointer setEmitModified(false); + // update the hash of the first block + m_fileBlockHash.clear(); + auto fileBlockData = dbFile.peek(kFileBlockToHashSizeBytes); + if (fileBlockData.size() != kFileBlockToHashSizeBytes) { + if (dbFile.size() >= kFileBlockToHashSizeBytes) { + if (error) { + *error = tr("Database file read error."); + } + return false; + } + } else { + m_fileBlockHash = QCryptographicHash::hash(fileBlockData, QCryptographicHash::Md5); + } + KeePass2Reader reader; if (!reader.readDatabase(&dbFile, std::move(key), this)) { if (error) { @@ -258,14 +278,33 @@ bool Database::saveAs(const QString& filePath, SaveAction action, const QString& return false; } - if (filePath == m_data.filePath) { - // Fail-safe check to make sure we don't overwrite underlying file changes - // that have not yet triggered a file reload/merge operation. - if (!m_fileWatcher->hasSameFileChecksum()) { - if (error) { - *error = tr("Database file has unmerged changes."); + // Make sure we don't overwrite external modifications unless explicitly allowed + if (!m_ignoreFileChangesUntilSaved && !m_fileBlockHash.isEmpty() && filePath == m_data.filePath) { + QFile dbFile(filePath); + if (dbFile.exists()) { + if (!dbFile.open(QIODevice::ReadOnly)) { + if (error) { + *error = tr("Unable to open file %1.").arg(filePath); + } + return false; + } + auto fileBlockData = dbFile.read(kFileBlockToHashSizeBytes); + if (fileBlockData.size() == kFileBlockToHashSizeBytes) { + auto hash = QCryptographicHash::hash(fileBlockData, QCryptographicHash::Md5); + if (m_fileBlockHash != hash) { + if (error) { + *error = tr("Database file has unmerged changes."); + } + // emit the databaseFileChanged(true) signal async + QMetaObject::invokeMethod(this, "databaseFileChanged", Qt::QueuedConnection, Q_ARG(bool, true)); + return false; + } + } else if (dbFile.size() >= kFileBlockToHashSizeBytes) { + if (error) { + *error = tr("Database file read error."); + } + return false; } - return false; } } @@ -300,7 +339,7 @@ bool Database::saveAs(const QString& filePath, SaveAction action, const QString& SetFileAttributes(realFilePath.toStdString().c_str(), FILE_ATTRIBUTE_HIDDEN); } #endif - + m_ignoreFileChangesUntilSaved = false; m_fileWatcher->start(realFilePath, 30, 1); } else { // Saving failed, don't rewatch file since it does not represent our database @@ -316,26 +355,29 @@ bool Database::performSave(const QString& filePath, SaveAction action, const QSt backupDatabase(filePath, backupFilePath); } -#if QT_VERSION >= QT_VERSION_CHECK(5, 10, 0) QFileInfo info(filePath); auto createTime = info.exists() ? info.birthTime() : QDateTime::currentDateTime(); -#endif switch (action) { case Atomic: { QSaveFile saveFile(filePath); if (saveFile.open(QIODevice::WriteOnly)) { + HashingStream hashingStream(&saveFile, QCryptographicHash::Md5, kFileBlockToHashSizeBytes); + if (!hashingStream.open(QIODevice::WriteOnly)) { + return false; + } // write the database to the file - if (!writeDatabase(&saveFile, error)) { + if (!writeDatabase(&hashingStream, error)) { return false; } -#if QT_VERSION >= QT_VERSION_CHECK(5, 10, 0) // Retain original creation time saveFile.setFileTime(createTime, QFile::FileBirthTime); -#endif if (saveFile.commit()) { + // store the new hash + m_fileBlockHash = hashingStream.hashingResult(); + // successfully saved database file return true; } @@ -349,8 +391,12 @@ bool Database::performSave(const QString& filePath, SaveAction action, const QSt case TempFile: { QTemporaryFile tempFile; if (tempFile.open()) { + HashingStream hashingStream(&tempFile, QCryptographicHash::Md5, kFileBlockToHashSizeBytes); + if (!hashingStream.open(QIODevice::WriteOnly)) { + return false; + } // write the database to the file - if (!writeDatabase(&tempFile, error)) { + if (!writeDatabase(&hashingStream, error)) { return false; } tempFile.close(); // flush to disk @@ -366,10 +412,10 @@ bool Database::performSave(const QString& filePath, SaveAction action, const QSt // successfully saved the database tempFile.setAutoRemove(false); QFile::setPermissions(filePath, perms); -#if QT_VERSION >= QT_VERSION_CHECK(5, 10, 0) - // Retain orginal creation time + // Retain original creation time tempFile.setFileTime(createTime, QFile::FileBirthTime); -#endif + // store the new hash + m_fileBlockHash = hashingStream.hashingResult(); return true; } else if (backupFilePath.isEmpty() || !restoreDatabase(filePath, backupFilePath)) { // Failed to copy new database in place, and @@ -388,13 +434,26 @@ bool Database::performSave(const QString& filePath, SaveAction action, const QSt break; } case DirectWrite: { + QBuffer dbBuffer; + dbBuffer.open(QIODevice::WriteOnly); + HashingStream hashingStream(&dbBuffer, QCryptographicHash::Md5, kFileBlockToHashSizeBytes); + if (!hashingStream.open(QIODevice::WriteOnly)) { + if (error) { + *error = hashingStream.errorString(); + } + return false; + } + if (!writeDatabase(&hashingStream, error)) { + return false; + } + // Open the original database file for direct-write QFile dbFile(filePath); if (dbFile.open(QIODevice::WriteOnly | QIODevice::Truncate)) { - if (!writeDatabase(&dbFile, error)) { - return false; - } + dbFile.write(dbBuffer.data()); dbFile.close(); + // store the new hash + m_fileBlockHash = hashingStream.hashingResult(); return true; } if (error) { @@ -512,6 +571,9 @@ void Database::releaseData() m_deletedObjects.clear(); m_commonUsernames.clear(); m_tagList.clear(); + + m_fileBlockHash.clear(); + m_ignoreFileChangesUntilSaved = false; } /** @@ -648,10 +710,33 @@ void Database::setFilePath(const QString& filePath) m_data.filePath = filePath; // Don't watch for changes until the next open or save operation m_fileWatcher->stop(); + m_ignoreFileChangesUntilSaved = false; emit filePathChanged(oldPath, filePath); } } +const QByteArray& Database::fileBlockHash() const +{ + return m_fileBlockHash; +} + +void Database::setIgnoreFileChangesUntilSaved(bool ignore) +{ + if (m_ignoreFileChangesUntilSaved != ignore) { + m_ignoreFileChangesUntilSaved = ignore; + if (ignore) { + m_fileWatcher->pause(); + } else { + m_fileWatcher->resume(); + } + } +} + +bool Database::ignoreFileChangesUntilSaved() const +{ + return m_ignoreFileChangesUntilSaved; +} + QList Database::deletedObjects() { return m_deletedObjects; @@ -740,8 +825,13 @@ void Database::updateTagList() } } - m_tagList = tagSet.toList(); - m_tagList.sort(); + m_tagList = tagSet.values(); + + QCollator collator; + collator.setNumericMode(true); + collator.setCaseSensitivity(Qt::CaseInsensitive); + std::sort(m_tagList.begin(), m_tagList.end(), collator); + emit tagListUpdated(); } @@ -1036,3 +1126,79 @@ void Database::stopModifiedTimer() { QMetaObject::invokeMethod(&m_modifiedTimer, "stop"); } + +QUuid Database::publicUuid() +{ + // This feature requires KDBX4 + if (m_data.formatVersion < KeePass2::FILE_VERSION_4) { + // Return the file path hash as a UUID for KDBX3 + QCryptographicHash hasher(QCryptographicHash::Sha256); + hasher.addData(filePath().toUtf8()); + return QUuid::fromRfc4122(hasher.result().left(16)); + } + + if (!publicCustomData().contains("KPXC_PUBLIC_UUID")) { + publicCustomData().insert("KPXC_PUBLIC_UUID", QUuid::createUuid().toRfc4122()); + markAsModified(); + } + + return QUuid::fromRfc4122(publicCustomData()["KPXC_PUBLIC_UUID"].toByteArray()); +} + +QString Database::publicName() +{ + return publicCustomData().value("KPXC_PUBLIC_NAME").toString(); +} + +void Database::setPublicName(const QString& name) +{ + if (name.isEmpty()) { + publicCustomData().remove("KPXC_PUBLIC_NAME"); + } else { + publicCustomData().insert("KPXC_PUBLIC_NAME", name); + } + markAsModified(); +} + +QString Database::publicColor() +{ + return publicCustomData().value("KPXC_PUBLIC_COLOR").toString(); +} + +void Database::setPublicColor(const QString& color) +{ + if (color.isEmpty()) { + publicCustomData().remove("KPXC_PUBLIC_COLOR"); + } else { + publicCustomData().insert("KPXC_PUBLIC_COLOR", color); + } + markAsModified(); +} + +int Database::publicIcon() +{ + if (publicCustomData().contains("KPXC_PUBLIC_ICON")) { + return publicCustomData().value("KPXC_PUBLIC_ICON").toInt(); + } + return -1; +} + +void Database::setPublicIcon(int iconIndex) +{ + if (iconIndex < 0) { + publicCustomData().remove("KPXC_PUBLIC_ICON"); + } else { + publicCustomData().insert("KPXC_PUBLIC_ICON", iconIndex); + } + markAsModified(); +} + +void Database::markAsTemporaryDatabase() +{ + m_isTemporaryDatabase = true; +} + +bool Database::isTemporaryDatabase() +{ + return m_isTemporaryDatabase; +} diff --git a/src/core/Database.h b/src/core/Database.h index 35546f743..0d183e778 100644 --- a/src/core/Database.h +++ b/src/core/Database.h @@ -75,6 +75,9 @@ public: ~Database() override; private: + // size of the block of file data to hash for detecting external changes + static const quint32 kFileBlockToHashSizeBytes = 1024; // 1 KiB + bool writeDatabase(QIODevice* device, QString* error = nullptr); bool backupDatabase(const QString& filePath, const QString& destinationFilePath); bool restoreDatabase(const QString& filePath, const QString& fromBackupFilePath); @@ -102,11 +105,23 @@ public: bool hasNonDataChanges() const; bool isSaving(); + QUuid publicUuid(); QUuid uuid() const; QString filePath() const; QString canonicalFilePath() const; void setFilePath(const QString& filePath); + const QByteArray& fileBlockHash() const; + void setIgnoreFileChangesUntilSaved(bool ignore); + bool ignoreFileChangesUntilSaved() const; + + QString publicName(); + void setPublicName(const QString& name); + QString publicColor(); + void setPublicColor(const QString& color); + int publicIcon(); + void setPublicIcon(int iconIndex); + Metadata* metadata(); const Metadata* metadata() const; Group* rootGroup(); @@ -149,6 +164,9 @@ public: bool changeKdf(const QSharedPointer& kdf); QByteArray transformedDatabaseKey() const; + void markAsTemporaryDatabase(); + bool isTemporaryDatabase(); + static Database* databaseByUuid(const QUuid& uuid); public slots: @@ -170,7 +188,7 @@ signals: void databaseOpened(); void databaseSaved(); void databaseDiscarded(); - void databaseFileChanged(); + void databaseFileChanged(bool triggeredBySave); void databaseNonDataChanged(); void tagListUpdated(); @@ -222,6 +240,8 @@ private: void startModifiedTimer(); void stopModifiedTimer(); + QByteArray m_fileBlockHash; + bool m_ignoreFileChangesUntilSaved; QPointer const m_metadata; DatabaseData m_data; QPointer m_rootGroup; @@ -232,6 +252,7 @@ private: bool m_modified = false; bool m_hasNonDataChange = false; QString m_keyError; + bool m_isTemporaryDatabase = false; QStringList m_commonUsernames; QStringList m_tagList; diff --git a/src/core/Entry.cpp b/src/core/Entry.cpp index db1542c6c..1ef96aabe 100644 --- a/src/core/Entry.cpp +++ b/src/core/Entry.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2023 KeePassXC Team + * Copyright (C) 2024 KeePassXC Team * Copyright (C) 2010 Felix Geyer * * This program is free software: you can redistribute it and/or modify @@ -20,6 +20,7 @@ #include "core/Config.h" #include "core/Database.h" +#include "core/Global.h" #include "core/Group.h" #include "core/Metadata.h" #include "core/PasswordHealth.h" @@ -28,12 +29,18 @@ #include #include +#include #include const int Entry::DefaultIconNumber = 0; -const int Entry::ResolveMaximumDepth = 10; -const QString Entry::AutoTypeSequenceUsername = "{USERNAME}{ENTER}"; -const QString Entry::AutoTypeSequencePassword = "{PASSWORD}{ENTER}"; + +namespace +{ + const int ResolveMaximumDepth = 10; + const QString AutoTypeSequenceUsername = "{USERNAME}{ENTER}"; + const QString AutoTypeSequencePassword = "{PASSWORD}{ENTER}"; + const QRegularExpression TagDelimiterRegex(R"([,;\t])"); +} // namespace Entry::Entry() : m_attributes(new EntryAttributes(this)) @@ -286,7 +293,7 @@ QString Entry::effectiveAutoTypeSequence() const /** * Retrieve the Auto-Type sequences matches for a given windowTitle - * This returns a list with priority ordering. If you don't want duplicates call .toSet() on it. + * This returns a list with priority ordering. If you don't want duplicates, convert it to a QSet. */ QList Entry::autoTypeSequences(const QString& windowTitle) const { @@ -374,16 +381,32 @@ QString Entry::url() const return m_attributes->value(EntryAttributes::URLKey); } +QString Entry::resolveUrl() const +{ + const auto entryUrl = url(); + if (entryUrl.isEmpty()) { + return {}; + } + + return EntryAttributes::matchReference(entryUrl).hasMatch() ? resolveMultiplePlaceholders(entryUrl) : entryUrl; +} + QStringList Entry::getAllUrls() const { QStringList urlList; - auto entryUrl = url(); + const auto entryUrl = resolveUrl(); if (!entryUrl.isEmpty()) { - urlList << (EntryAttributes::matchReference(entryUrl).hasMatch() ? resolveMultiplePlaceholders(entryUrl) - : entryUrl); + urlList << entryUrl; } + return urlList << getAdditionalUrls(); +} + +QStringList Entry::getAdditionalUrls() const +{ + QStringList urlList; + for (const auto& key : m_attributes->keys()) { if (key.startsWith(EntryAttributes::AdditionalUrlAttribute) || key == QString("%1_RELYING_PARTY").arg(EntryAttributes::PasskeyAttribute)) { @@ -432,14 +455,11 @@ QString Entry::attribute(const QString& key) const int Entry::size() const { int size = 0; - const QRegularExpression delimiter(",|:|;"); - - size += this->attributes()->attributesSize(); - size += this->autoTypeAssociations()->associationsSize(); - size += this->attachments()->attachmentsSize(); - size += this->customData()->dataSize(); - const QStringList tags = this->tags().split(delimiter, QString::SkipEmptyParts); - for (const QString& tag : tags) { + size += attributes()->attributesSize(); + size += autoTypeAssociations()->associationsSize(); + size += attachments()->attachmentsSize(); + size += customData()->dataSize(); + for (const QString& tag : tags().split(TagDelimiterRegex, Qt::SkipEmptyParts)) { size += tag.toUtf8().size(); } @@ -456,6 +476,12 @@ bool Entry::willExpireInDays(int days) const return m_data.timeInfo.expires() && m_data.timeInfo.expiryTime() < Clock::currentDateTime().addDays(days); } +void Entry::expireNow() +{ + setExpiryTime(Clock::currentDateTimeUtc()); + setExpires(true); +} + bool Entry::isRecycled() const { const Database* db = database(); @@ -482,8 +508,7 @@ bool Entry::isAttributeReferenceOf(const QString& key, const QUuid& uuid) const bool Entry::hasReferences() const { - const QList keyList = EntryAttributes::DefaultAttributes; - for (const QString& key : keyList) { + for (const QString& key : EntryAttributes::DefaultAttributes) { if (m_attributes->isReference(key)) { return true; } @@ -493,8 +518,7 @@ bool Entry::hasReferences() const bool Entry::hasReferencesTo(const QUuid& uuid) const { - const QList keyList = EntryAttributes::DefaultAttributes; - for (const QString& key : keyList) { + for (const QString& key : EntryAttributes::DefaultAttributes) { if (isAttributeReferenceOf(key, uuid)) { return true; } @@ -546,15 +570,30 @@ bool Entry::hasTotp() const return !m_data.totpSettings.isNull(); } +bool Entry::hasValidTotp() const +{ + auto error = Totp::checkValidSettings(m_data.totpSettings); + return error.isEmpty(); +} + bool Entry::hasPasskey() const { return m_attributes->hasPasskey(); } -QString Entry::totp() const +void Entry::removePasskey() +{ + m_attributes->removePasskeyAttributes(); + removeTag(tr("Passkey")); +} + +QString Entry::totp(bool* isValid) const { if (hasTotp()) { - return Totp::generateTotp(m_data.totpSettings); + return Totp::generateTotp(m_data.totpSettings, isValid); + } + if (isValid) { + *isValid = false; } return {}; } @@ -589,6 +628,11 @@ void Entry::updateTotp() m_attributes->value(Totp::ATTRIBUTE_SEED)); } else if (m_attributes->contains(Totp::ATTRIBUTE_OTP)) { m_data.totpSettings = Totp::parseSettings(m_attributes->value(Totp::ATTRIBUTE_OTP)); + } else if (m_attributes->contains(Totp::KP2_TOTP_SECRET)) { + m_data.totpSettings = Totp::fromKeePass2Totp(m_attributes->value(Totp::KP2_TOTP_SECRET), + m_attributes->value(Totp::KP2_TOTP_ALGORITHM), + m_attributes->value(Totp::KP2_TOTP_LENGTH), + m_attributes->value(Totp::KP2_TOTP_PERIOD)); } else { m_data.totpSettings.reset(); } @@ -664,15 +708,13 @@ void Entry::setOverrideUrl(const QString& url) void Entry::setTags(const QString& tags) { - static QRegExp rx("(\\,|\\t|\\;)"); - auto taglist = tags.split(rx, QString::SkipEmptyParts); + auto taglist = tags.split(TagDelimiterRegex, Qt::SkipEmptyParts); // Trim whitespace before/after tag text - for (auto itr = taglist.begin(); itr != taglist.end(); ++itr) { - *itr = itr->trimmed(); + for (auto& tag : taglist) { + tag = tag.trimmed(); } // Remove duplicates - auto tagSet = QSet::fromList(taglist); - taglist = tagSet.toList(); + taglist = Tools::asSet(taglist).values(); // Sort alphabetically taglist.sort(); set(m_data.tags, taglist); @@ -681,7 +723,7 @@ void Entry::setTags(const QString& tags) void Entry::addTag(const QString& tag) { auto cleanTag = tag.trimmed(); - cleanTag.remove(QRegExp("(\\,|\\t|\\;)")); + cleanTag.remove(TagDelimiterRegex); auto taglist = m_data.tags; if (!taglist.contains(cleanTag)) { @@ -694,7 +736,7 @@ void Entry::addTag(const QString& tag) void Entry::removeTag(const QString& tag) { auto cleanTag = tag.trimmed(); - cleanTag.remove(QRegExp("(\\,|\\t|\\;)")); + cleanTag.remove(TagDelimiterRegex); auto taglist = m_data.tags; if (taglist.removeAll(tag) > 0) { @@ -796,10 +838,21 @@ void Entry::addHistoryItem(Entry* entry) { Q_ASSERT(!entry->parent()); + entry->setHistoryOwner(this); m_history.append(entry); emitModified(); } +void Entry::setHistoryOwner(Entry* entry) +{ + m_historyOwner = entry; +} + +Entry* Entry::historyOwner() const +{ + return m_historyOwner; +} + void Entry::removeHistoryItems(const QList& historyEntries) { if (historyEntries.isEmpty()) { @@ -846,7 +899,6 @@ void Entry::truncateHistory() int histMaxSize = db->metadata()->historyMaxSize(); if (histMaxSize > -1) { int size = 0; - QSet foundAttachments = attachments()->values(); QMutableListIterator i(m_history); i.toBack(); @@ -856,7 +908,6 @@ void Entry::truncateHistory() // don't calculate size if it's already above the maximum if (size <= histMaxSize) { size += historyItem->size(); - foundAttachments += historyItem->attachments()->values(); } if (size > histMaxSize) { @@ -910,7 +961,7 @@ bool Entry::equals(const Entry* other, CompareItemOptions options) const Entry* Entry::clone(CloneFlags flags) const { - Entry* entry = new Entry(); + auto entry = new Entry(); entry->setUpdateTimeinfo(false); if (flags & CloneNewUuid) { entry->m_uuid = QUuid::createUuid(); @@ -1010,31 +1061,29 @@ void Entry::updateModifiedSinceBegin() QString Entry::resolveMultiplePlaceholdersRecursive(const QString& str, int maxDepth) const { - static QRegularExpression placeholderRegEx("(\\{[^\\}]+?\\})", QRegularExpression::CaseInsensitiveOption); + static const QRegularExpression placeholderRegEx("({(?>[^{}]+?|(?1))+?})"); - if (maxDepth <= 0) { + if (--maxDepth < 0) { qWarning("Maximum depth of replacement has been reached. Entry uuid: %s", uuid().toString().toLatin1().data()); return str; } - QString result = str; + QString result; auto matches = placeholderRegEx.globalMatch(str); + int capEnd = 0; while (matches.hasNext()) { - auto match = matches.next(); - const auto found = match.captured(1); - result.replace(found, resolvePlaceholderRecursive(found, maxDepth - 1)); + const auto match = matches.next(); + result += str.midRef(capEnd, match.capturedStart() - capEnd); + result += resolvePlaceholderRecursive(match.captured(), maxDepth); + capEnd = match.capturedEnd(); } - - if (result != str) { - result = resolveMultiplePlaceholdersRecursive(result, maxDepth - 1); - } - + result += str.rightRef(str.length() - capEnd); return result; } QString Entry::resolvePlaceholderRecursive(const QString& placeholder, int maxDepth) const { - if (maxDepth <= 0) { + if (--maxDepth < 0) { qWarning("Maximum depth of replacement has been reached. Entry uuid: %s", uuid().toString().toLatin1().data()); return placeholder; } @@ -1042,33 +1091,20 @@ QString Entry::resolvePlaceholderRecursive(const QString& placeholder, int maxDe const PlaceholderType typeOfPlaceholder = placeholderType(placeholder); switch (typeOfPlaceholder) { case PlaceholderType::NotPlaceholder: - case PlaceholderType::Unknown: - return resolveMultiplePlaceholdersRecursive(placeholder, maxDepth - 1); + return resolveMultiplePlaceholdersRecursive(placeholder, maxDepth); + case PlaceholderType::Unknown: { + return "{" % resolveMultiplePlaceholdersRecursive(placeholder.mid(1, placeholder.length() - 2), maxDepth) % "}"; + } case PlaceholderType::Title: - if (placeholderType(title()) == PlaceholderType::Title) { - return title(); - } - return resolveMultiplePlaceholdersRecursive(title(), maxDepth - 1); + return resolveMultiplePlaceholdersRecursive(title(), maxDepth); case PlaceholderType::UserName: - if (placeholderType(username()) == PlaceholderType::UserName) { - return username(); - } - return resolveMultiplePlaceholdersRecursive(username(), maxDepth - 1); + return resolveMultiplePlaceholdersRecursive(username(), maxDepth); case PlaceholderType::Password: - if (placeholderType(password()) == PlaceholderType::Password) { - return password(); - } - return resolveMultiplePlaceholdersRecursive(password(), maxDepth - 1); + return resolveMultiplePlaceholdersRecursive(password(), maxDepth); case PlaceholderType::Notes: - if (placeholderType(notes()) == PlaceholderType::Notes) { - return notes(); - } - return resolveMultiplePlaceholdersRecursive(notes(), maxDepth - 1); + return resolveMultiplePlaceholdersRecursive(notes(), maxDepth); case PlaceholderType::Url: - if (placeholderType(url()) == PlaceholderType::Url) { - return url(); - } - return resolveMultiplePlaceholdersRecursive(url(), maxDepth - 1); + return resolveMultiplePlaceholdersRecursive(url(), maxDepth); case PlaceholderType::DbDir: { QFileInfo fileInfo(database()->filePath()); return fileInfo.absoluteDir().absolutePath(); @@ -1083,7 +1119,7 @@ QString Entry::resolvePlaceholderRecursive(const QString& placeholder, int maxDe case PlaceholderType::UrlUserInfo: case PlaceholderType::UrlUserName: case PlaceholderType::UrlPassword: { - const QString strUrl = resolveMultiplePlaceholdersRecursive(url(), maxDepth - 1); + const QString strUrl = resolveMultiplePlaceholdersRecursive(url(), maxDepth); return resolveUrlPlaceholder(strUrl, typeOfPlaceholder); } case PlaceholderType::Totp: @@ -1091,10 +1127,11 @@ QString Entry::resolvePlaceholderRecursive(const QString& placeholder, int maxDe return totp(); case PlaceholderType::CustomAttribute: { const QString key = placeholder.mid(3, placeholder.length() - 4); // {S:attr} => mid(3, len - 4) - return attributes()->hasKey(key) ? attributes()->value(key) : QString(); + return attributes()->hasKey(key) ? resolveMultiplePlaceholdersRecursive(attributes()->value(key), maxDepth) + : QString(); } case PlaceholderType::Reference: - return resolveReferencePlaceholderRecursive(placeholder, maxDepth); + return resolveReferencePlaceholderRecursive(placeholder, ++maxDepth); case PlaceholderType::DateTimeSimple: case PlaceholderType::DateTimeYear: case PlaceholderType::DateTimeMonth: @@ -1109,7 +1146,11 @@ QString Entry::resolvePlaceholderRecursive(const QString& placeholder, int maxDe case PlaceholderType::DateTimeUtcHour: case PlaceholderType::DateTimeUtcMinute: case PlaceholderType::DateTimeUtcSecond: - return resolveMultiplePlaceholdersRecursive(resolveDateTimePlaceholder(typeOfPlaceholder), maxDepth - 1); + return resolveMultiplePlaceholdersRecursive(resolveDateTimePlaceholder(typeOfPlaceholder), maxDepth); + case PlaceholderType::Conversion: + return resolveMultiplePlaceholdersRecursive(resolveConversionPlaceholder(placeholder), maxDepth); + case PlaceholderType::Regex: + return resolveMultiplePlaceholdersRecursive(resolveRegexPlaceholder(placeholder), maxDepth); } return placeholder; @@ -1117,65 +1158,134 @@ QString Entry::resolvePlaceholderRecursive(const QString& placeholder, int maxDe QString Entry::resolveDateTimePlaceholder(Entry::PlaceholderType placeholderType) const { - QDateTime time = Clock::currentDateTime(); - QDateTime time_utc = Clock::currentDateTimeUtc(); - QString date_formatted{}; + const QDateTime time = Clock::currentDateTime(); + const QDateTime time_utc = Clock::currentDateTimeUtc(); switch (placeholderType) { case PlaceholderType::DateTimeSimple: - date_formatted = time.toString("yyyyMMddhhmmss"); - break; + return time.toString("yyyyMMddhhmmss"); case PlaceholderType::DateTimeYear: - date_formatted = time.toString("yyyy"); - break; + return time.toString("yyyy"); case PlaceholderType::DateTimeMonth: - date_formatted = time.toString("MM"); - break; + return time.toString("MM"); case PlaceholderType::DateTimeDay: - date_formatted = time.toString("dd"); - break; + return time.toString("dd"); case PlaceholderType::DateTimeHour: - date_formatted = time.toString("hh"); - break; + return time.toString("hh"); case PlaceholderType::DateTimeMinute: - date_formatted = time.toString("mm"); - break; + return time.toString("mm"); case PlaceholderType::DateTimeSecond: - date_formatted = time.toString("ss"); - break; + return time.toString("ss"); case PlaceholderType::DateTimeUtcSimple: - date_formatted = time_utc.toString("yyyyMMddhhmmss"); - break; + return time_utc.toString("yyyyMMddhhmmss"); case PlaceholderType::DateTimeUtcYear: - date_formatted = time_utc.toString("yyyy"); - break; + return time_utc.toString("yyyy"); case PlaceholderType::DateTimeUtcMonth: - date_formatted = time_utc.toString("MM"); - break; + return time_utc.toString("MM"); case PlaceholderType::DateTimeUtcDay: - date_formatted = time_utc.toString("dd"); - break; + return time_utc.toString("dd"); case PlaceholderType::DateTimeUtcHour: - date_formatted = time_utc.toString("hh"); - break; + return time_utc.toString("hh"); case PlaceholderType::DateTimeUtcMinute: - date_formatted = time_utc.toString("mm"); - break; + return time_utc.toString("mm"); case PlaceholderType::DateTimeUtcSecond: - date_formatted = time_utc.toString("ss"); - break; + return time_utc.toString("ss"); default: { Q_ASSERT_X(false, "Entry::resolveDateTimePlaceholder", "Bad DateTime placeholder type"); break; } } - return date_formatted; + return {}; +} + +QString Entry::resolveConversionPlaceholder(const QString& str, QString* error) const +{ + if (error) { + error->clear(); + } + + // Extract the inner conversion from the placeholder + QRegularExpression conversionRegEx("^{?t-conv:(.*)}?$", QRegularExpression::CaseInsensitiveOption); + auto placeholder = conversionRegEx.match(str).captured(1); + if (!placeholder.isEmpty()) { + // Determine the separator character and split, include empty groups + auto sep = placeholder[0]; + auto parts = placeholder.split(sep); + if (parts.size() >= 4) { + auto resolved = resolveMultiplePlaceholders(parts[1]); + auto type = parts[2].toLower(); + + if (type == "base64") { + resolved = resolved.toUtf8().toBase64(); + } else if (type == "hex") { + resolved = resolved.toUtf8().toHex(); + } else if (type == "uri") { + resolved = QUrl::toPercentEncoding(resolved.toUtf8()); + } else if (type == "uri-dec") { + resolved = QUrl::fromPercentEncoding(resolved.toUtf8()); + } else if (type.startsWith("u")) { + resolved = resolved.toUpper(); + } else if (type.startsWith("l")) { + resolved = resolved.toLower(); + } else { + if (error) { + *error = tr("Invalid conversion type: %1").arg(type); + } + return {}; + } + return resolved; + } + } + + if (error) { + *error = tr("Invalid conversion syntax: %1").arg(str); + } + return {}; +} + +QString Entry::resolveRegexPlaceholder(const QString& str, QString* error) const +{ + if (error) { + error->clear(); + } + + // Extract the inner regex from the placeholder + QRegularExpression conversionRegEx("^{?t-replace-rx:(.*)}?$", QRegularExpression::CaseInsensitiveOption); + auto placeholder = conversionRegEx.match(str).captured(1); + if (!placeholder.isEmpty()) { + // Determine the separator character and split, include empty groups + auto sep = placeholder[0]; + auto parts = placeholder.split(sep); + if (parts.size() >= 5) { + auto resolvedText = resolveMultiplePlaceholders(parts[1]); + auto resolvedSearch = resolveMultiplePlaceholders(parts[2]); + auto resolvedReplace = resolveMultiplePlaceholders(parts[3]); + // Replace $ with \\ to support Qt substitutions + resolvedReplace.replace(QRegularExpression(R"(\$(\d+))"), R"(\\1)"); + + auto searchRegex = QRegularExpression(resolvedSearch); + if (!searchRegex.isValid()) { + if (error) { + *error = + tr("Invalid regular expression syntax %1\n%2").arg(resolvedSearch, searchRegex.errorString()); + } + return {}; + } + + return resolvedText.replace(searchRegex, resolvedReplace); + } + } + + if (error) { + *error = tr("Invalid conversion syntax: %1").arg(str); + } + return {}; } QString Entry::resolveReferencePlaceholderRecursive(const QString& placeholder, int maxDepth) const { - if (maxDepth <= 0) { + if (--maxDepth < 0) { qWarning("Maximum depth of replacement has been reached. Entry uuid: %s", uuid().toString().toLatin1().data()); return placeholder; } @@ -1183,7 +1293,7 @@ QString Entry::resolveReferencePlaceholderRecursive(const QString& placeholder, // resolving references in format: {REF:@:} // using format from http://keepass.info/help/base/fieldrefs.html at the time of writing - QRegularExpressionMatch match = EntryAttributes::matchReference(placeholder); + const QRegularExpressionMatch match = EntryAttributes::matchReference(placeholder); if (!match.hasMatch() || !m_group || !m_group->database()) { return placeholder; } @@ -1203,7 +1313,7 @@ QString Entry::resolveReferencePlaceholderRecursive(const QString& placeholder, // Referencing fields of other entries only works with standard fields, not with custom user strings. // If you want to reference a custom user string, you need to place a redirection in a standard field // of the entry with the custom string, using {S:}, and reference the standard field. - result = refEntry->resolveMultiplePlaceholdersRecursive(result, maxDepth - 1); + result = refEntry->resolveMultiplePlaceholdersRecursive(result, maxDepth); } return result; @@ -1227,7 +1337,7 @@ QString Entry::referenceFieldValue(EntryReferenceType referenceType) const default: break; } - return QString(); + return {}; } void Entry::moveUp() @@ -1312,9 +1422,7 @@ Database* Entry::database() QString Entry::maskPasswordPlaceholders(const QString& str) const { - QString result = str; - result.replace(QRegExp("(\\{PASSWORD\\})", Qt::CaseInsensitive, QRegExp::RegExp2), "******"); - return result; + return QString{str}.replace(QStringLiteral("{PASSWORD}"), QStringLiteral("******"), Qt::CaseInsensitive); } Entry* Entry::resolveReference(const QString& str) const @@ -1344,7 +1452,7 @@ QString Entry::resolvePlaceholder(const QString& placeholder) const QString Entry::resolveUrlPlaceholder(const QString& str, Entry::PlaceholderType placeholderType) const { if (str.isEmpty()) { - return QString(); + return {}; } const QUrl qurl(str); @@ -1375,20 +1483,26 @@ QString Entry::resolveUrlPlaceholder(const QString& str, Entry::PlaceholderType } } - return QString(); + return {}; } Entry::PlaceholderType Entry::placeholderType(const QString& placeholder) const { - if (!placeholder.startsWith(QLatin1Char('{')) || !placeholder.endsWith(QLatin1Char('}'))) { + if (!placeholder.startsWith(QStringLiteral("{")) || !placeholder.endsWith(QStringLiteral("}"))) { return PlaceholderType::NotPlaceholder; } - if (placeholder.startsWith(QLatin1Literal("{S:"))) { + if (placeholder.startsWith(QStringLiteral("{S:"))) { return PlaceholderType::CustomAttribute; } - if (placeholder.startsWith(QLatin1Literal("{REF:"))) { + if (placeholder.startsWith(QStringLiteral("{REF:"))) { return PlaceholderType::Reference; } + if (placeholder.startsWith(QStringLiteral("{T-CONV:"), Qt::CaseInsensitive)) { + return PlaceholderType::Conversion; + } + if (placeholder.startsWith(QStringLiteral("{T-REPLACE-RX:"), Qt::CaseInsensitive)) { + return PlaceholderType::Regex; + } static const QMap placeholders{ {QStringLiteral("{TITLE}"), PlaceholderType::Title}, @@ -1432,22 +1546,24 @@ QString Entry::resolveUrl(const QString& url) const { QString newUrl = url; - QRegExp fileRegEx("^([a-z]:)?[\\\\/]", Qt::CaseInsensitive, QRegExp::RegExp2); - if (fileRegEx.indexIn(newUrl) != -1) { + static const QRegularExpression fileRegEx(R"(^(?:[A-Za-z]:)?[\\/])"); + if (url.contains(fileRegEx)) { // Match possible file paths without the scheme and convert it to a file URL newUrl = QDir::fromNativeSeparators(newUrl); newUrl = QUrl::fromLocalFile(newUrl).toString(); - } else if (newUrl.startsWith("cmd://")) { + } else if (url.startsWith("cmd://")) { QStringList cmdList = newUrl.split(" "); for (int i = 1; i < cmdList.size(); ++i) { + QString& cmd = cmdList[i]; // Don't pass arguments to the resolveUrl function (they look like URL's) - if (!cmdList[i].startsWith("-") && !cmdList[i].startsWith("/")) { - return resolveUrl(cmdList[i].remove(QRegExp("'|\""))); + if (!cmd.startsWith("-") && !cmd.startsWith("/")) { + static const QRegularExpression quotesRegEx("['\"]"); + return resolveUrl(cmd.remove(quotesRegEx)); } } // No URL in this command - return QString(""); + return {}; } if (!newUrl.isEmpty() && !newUrl.contains("://")) { @@ -1456,13 +1572,13 @@ QString Entry::resolveUrl(const QString& url) const } // Validate the URL - QUrl tempUrl = QUrl(newUrl); + QUrl tempUrl(newUrl); if (tempUrl.isValid() && (tempUrl.scheme() == "http" || tempUrl.scheme() == "https" || tempUrl.scheme() == "file")) { return tempUrl.url(); } - // No valid http URL's found + // No valid http URLs found return {}; } @@ -1551,7 +1667,7 @@ bool EntryData::equals(const EntryData& other, CompareItemOptions options) const return false; } } else if (totpSettings.isNull() != other.totpSettings.isNull()) { - // The existance of TOTP has changed between these entries + // The existence of TOTP has changed between these entries return false; } if (::compare(excludeFromReports, other.excludeFromReports, options) != 0) { diff --git a/src/core/Entry.h b/src/core/Entry.h index 796170514..ddf6b21a6 100644 --- a/src/core/Entry.h +++ b/src/core/Entry.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2023 KeePassXC Team + * Copyright (C) 2025 KeePassXC Team * Copyright (C) 2010 Felix Geyer * * This program is free software: you can redistribute it and/or modify @@ -79,7 +79,7 @@ class Entry : public ModifiableObject public: Entry(); - ~Entry(); + ~Entry() override; const QUuid& uuid() const; const QString uuidToHex() const; int iconNumber() const; @@ -100,14 +100,16 @@ public: const AutoTypeAssociations* autoTypeAssociations() const; QString title() const; QString url() const; + QString resolveUrl() const; QStringList getAllUrls() const; + QStringList getAdditionalUrls() const; QString webUrl() const; QString displayUrl() const; QString username() const; QString password() const; QString notes() const; QString attribute(const QString& key) const; - QString totp() const; + QString totp(bool* isValid = nullptr) const; QString totpSettingsString() const; QSharedPointer totpSettings() const; Group* previousParentGroup(); @@ -120,10 +122,14 @@ public: bool excludeFromReports() const; void setExcludeFromReports(bool state); - bool hasTotp() const; bool hasPasskey() const; + void removePasskey(); + + bool hasTotp() const; + bool hasValidTotp() const; bool isExpired() const; bool willExpireInDays(int days) const; + void expireNow(); bool isRecycled() const; bool isAttributeReference(const QString& key) const; bool isAttributeReferenceOf(const QString& key, const QUuid& uuid) const; @@ -166,6 +172,8 @@ public: QList historyItems(); const QList& historyItems() const; void addHistoryItem(Entry* entry); + void setHistoryOwner(Entry* entry); + Entry* historyOwner() const; void removeHistoryItems(const QList& historyEntries); void truncateHistory(); @@ -221,13 +229,12 @@ public: DateTimeUtcHour, DateTimeUtcMinute, DateTimeUtcSecond, - DbDir + DbDir, + Conversion, + Regex }; static const int DefaultIconNumber; - static const int ResolveMaximumDepth; - static const QString AutoTypeSequenceUsername; - static const QString AutoTypeSequencePassword; /** * Creates a duplicate of this entry except that the returned entry isn't @@ -243,6 +250,8 @@ public: QString resolvePlaceholder(const QString& str) const; QString resolveUrlPlaceholder(const QString& str, PlaceholderType placeholderType) const; QString resolveDateTimePlaceholder(PlaceholderType placeholderType) const; + QString resolveConversionPlaceholder(const QString& str, QString* error = nullptr) const; + QString resolveRegexPlaceholder(const QString& str, QString* error = nullptr) const; PlaceholderType placeholderType(const QString& placeholder) const; QString resolveUrl(const QString& url) const; @@ -295,6 +304,7 @@ private: QPointer m_autoTypeAssociations; QPointer m_customData; QList m_history; // Items sorted from oldest to newest + QPointer m_historyOwner; QScopedPointer m_tmpHistoryItem; bool m_modifiedSinceBegin; diff --git a/src/core/EntryAttachments.cpp b/src/core/EntryAttachments.cpp index c611f4413..110d1e52b 100644 --- a/src/core/EntryAttachments.cpp +++ b/src/core/EntryAttachments.cpp @@ -19,11 +19,13 @@ #include "config-keepassx.h" #include "core/Global.h" +#include "core/Tools.h" #include "crypto/Random.h" #include #include #include +#include #include #include #include @@ -50,7 +52,7 @@ bool EntryAttachments::hasKey(const QString& key) const QSet EntryAttachments::values() const { - return asConst(m_attachments).values().toSet(); + return Tools::asSet(m_attachments.values()); } QByteArray EntryAttachments::value(const QString& key) const @@ -235,8 +237,10 @@ bool EntryAttachments::openAttachment(const QString& key, QString* errorMessage) const bool saveOk = tmpFile.open() && tmpFile.setPermissions(QFile::ReadOwner | QFile::WriteOwner) && tmpFile.write(attachmentData) == attachmentData.size() && tmpFile.flush(); - if (!saveOk && errorMessage) { - *errorMessage = QString("%1 - %2").arg(key, tmpFile.errorString()); + if (!saveOk) { + if (errorMessage) { + *errorMessage = QString("%1 - %2").arg(key, tmpFile.errorString()); + } return false; } @@ -249,15 +253,35 @@ bool EntryAttachments::openAttachment(const QString& key, QString* errorMessage) watcher->start(tmpFile.fileName(), 5); connect(watcher.data(), &FileWatcher::fileChanged, this, &EntryAttachments::attachmentFileModified); m_attachmentFileWatchers.insert(tmpFile.fileName(), watcher); + } else if (auto path = m_openedAttachments.value(key); m_attachmentFileWatchers.contains(path)) { + // If we are already watching an open attachment file, overwrite it with the information from the entry + auto watcher = m_attachmentFileWatchers.value(path); + watcher->stop(); + + QFile file(path); + auto finally = qScopeGuard([&file, &watcher, &path] { + file.close(); + watcher->start(path, 5); + }); + + const auto attachmentData = value(key); + const bool saveOk = file.open(QIODevice::WriteOnly) && file.setPermissions(QFile::ReadOwner | QFile::WriteOwner) + && file.write(attachmentData) == attachmentData.size() && file.flush(); + + if (!saveOk) { + if (errorMessage) { + *errorMessage = QString("%1 - %2").arg(key, file.errorString()); + } + return false; + } } const bool openOk = QDesktopServices::openUrl(QUrl::fromLocalFile(m_openedAttachments.value(key))); if (!openOk && errorMessage) { *errorMessage = tr("Cannot open file \"%1\"").arg(key); - return false; } - return true; + return openOk; } void EntryAttachments::attachmentFileModified(const QString& path) diff --git a/src/core/EntryAttachments.h b/src/core/EntryAttachments.h index 1fc35df89..c07c9cbf7 100644 --- a/src/core/EntryAttachments.h +++ b/src/core/EntryAttachments.h @@ -34,7 +34,7 @@ class EntryAttachments : public ModifiableObject public: explicit EntryAttachments(QObject* parent = nullptr); - virtual ~EntryAttachments(); + ~EntryAttachments() override; QList keys() const; bool hasKey(const QString& key) const; QSet values() const; diff --git a/src/core/EntryAttributes.cpp b/src/core/EntryAttributes.cpp index 49c243ec1..5c1e1c3a0 100644 --- a/src/core/EntryAttributes.cpp +++ b/src/core/EntryAttributes.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2023 KeePassXC Team + * Copyright (C) 2024 KeePassXC Team * Copyright (C) 2012 Felix Geyer * * This program is free software: you can redistribute it and/or modify @@ -18,6 +18,7 @@ #include "EntryAttributes.h" #include "core/Global.h" +#include "core/Tools.h" #include #include @@ -35,7 +36,20 @@ const QString EntryAttributes::SearchTextGroupName = "SearchText"; const QString EntryAttributes::RememberCmdExecAttr = "_EXEC_CMD"; const QString EntryAttributes::AdditionalUrlAttribute = "KP2A_URL"; + +// Passkey related attributes const QString EntryAttributes::PasskeyAttribute = "KPEX_PASSKEY"; +const QString EntryAttributes::KPEX_PASSKEY_USERNAME = QStringLiteral("KPEX_PASSKEY_USERNAME"); +const QString EntryAttributes::KPEX_PASSKEY_CREDENTIAL_ID = QStringLiteral("KPEX_PASSKEY_CREDENTIAL_ID"); +const QString EntryAttributes::KPEX_PASSKEY_PRIVATE_KEY_PEM = QStringLiteral("KPEX_PASSKEY_PRIVATE_KEY_PEM"); +const QString EntryAttributes::KPEX_PASSKEY_RELYING_PARTY = QStringLiteral("KPEX_PASSKEY_RELYING_PARTY"); +const QString EntryAttributes::KPEX_PASSKEY_USER_HANDLE = QStringLiteral("KPEX_PASSKEY_USER_HANDLE"); +const QString EntryAttributes::KPEX_PASSKEY_PRIVATE_KEY_START = QStringLiteral("-----BEGIN PRIVATE KEY-----"); +const QString EntryAttributes::KPEX_PASSKEY_PRIVATE_KEY_END = QStringLiteral("-----END PRIVATE KEY-----"); + +// For compatibility with StrongBox +const QString EntryAttributes::KPEX_PASSKEY_GENERATED_USER_ID = QStringLiteral("KPEX_PASSKEY_GENERATED_USER_ID"); +const QString EntryAttributes::KPXC_PASSKEY_USERNAME = QStringLiteral("KPXC_PASSKEY_USERNAME"); EntryAttributes::EntryAttributes(QObject* parent) : ModifiableObject(parent) @@ -65,6 +79,16 @@ bool EntryAttributes::hasPasskey() const return false; } +void EntryAttributes::removePasskeyAttributes() +{ + const auto keyList = keys(); + for (const auto& key : keyList) { + if (isPasskeyAttribute(key)) { + remove(key); + } + } +} + QList EntryAttributes::customKeys() const { QList customKeys; @@ -238,7 +262,7 @@ void EntryAttributes::copyCustomKeysFrom(const EntryAttributes* other) bool EntryAttributes::areCustomKeysDifferent(const EntryAttributes* other) { // check if they are equal ignoring the order of the keys - if (keys().toSet() != other->keys().toSet()) { + if (Tools::asSet(keys()) != Tools::asSet(other->keys())) { return true; } @@ -299,8 +323,8 @@ bool EntryAttributes::operator!=(const EntryAttributes& other) const QRegularExpressionMatch EntryAttributes::matchReference(const QString& text) { - static QRegularExpression referenceRegExp( - "\\{REF:(?[TUPANI])@(?[TUPANIO]):(?[^}]+)\\}", + static const QRegularExpression referenceRegExp( + R"(\{REF:(?[TUPANI])@(?[TUPANIO]):(?[^}]+)\})", QRegularExpression::CaseInsensitiveOption); return referenceRegExp.match(text); diff --git a/src/core/EntryAttributes.h b/src/core/EntryAttributes.h index fecf6a993..d0767a4c1 100644 --- a/src/core/EntryAttributes.h +++ b/src/core/EntryAttributes.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2023 KeePassXC Team + * Copyright (C) 2024 KeePassXC Team * Copyright (C) 2012 Felix Geyer * * This program is free software: you can redistribute it and/or modify @@ -34,6 +34,7 @@ public: QList keys() const; bool hasKey(const QString& key) const; bool hasPasskey() const; + void removePasskeyAttributes(); QList customKeys() const; QString value(const QString& key) const; QList values(const QList& keys) const; @@ -63,7 +64,18 @@ public: static const QStringList DefaultAttributes; static const QString RememberCmdExecAttr; static const QString AdditionalUrlAttribute; + static const QString PasskeyAttribute; + static const QString KPXC_PASSKEY_USERNAME; + static const QString KPEX_PASSKEY_USERNAME; + static const QString KPEX_PASSKEY_CREDENTIAL_ID; + static const QString KPEX_PASSKEY_GENERATED_USER_ID; + static const QString KPEX_PASSKEY_PRIVATE_KEY_PEM; + static const QString KPEX_PASSKEY_RELYING_PARTY; + static const QString KPEX_PASSKEY_USER_HANDLE; + static const QString KPEX_PASSKEY_PRIVATE_KEY_START; + static const QString KPEX_PASSKEY_PRIVATE_KEY_END; + static bool isDefaultAttribute(const QString& key); static bool isPasskeyAttribute(const QString& key); diff --git a/src/core/EntrySearcher.cpp b/src/core/EntrySearcher.cpp index 13369a66d..cb9e135fe 100644 --- a/src/core/EntrySearcher.cpp +++ b/src/core/EntrySearcher.cpp @@ -203,7 +203,7 @@ bool EntrySearcher::searchEntryImpl(const Entry* entry) case Field::Is: if (term.word.startsWith("expired", Qt::CaseInsensitive)) { auto days = 0; - auto parts = term.word.split("-", QString::SkipEmptyParts); + auto parts = term.word.split("-", Qt::SkipEmptyParts); if (parts.length() >= 2) { days = parts[1].toInt(); } @@ -221,6 +221,13 @@ bool EntrySearcher::searchEntryImpl(const Entry* entry) } found = false; break; + case Field::Has: + if (term.word.compare("totp", Qt::CaseInsensitive) == 0) { + found = entry->hasTotp(); + break; + } + found = false; + break; case Field::Uuid: found = term.regex.match(entry->uuidToHex()).hasMatch(); break; @@ -260,6 +267,7 @@ void EntrySearcher::parseSearchTerms(const QString& searchString) {QStringLiteral("group"), Field::Group}, {QStringLiteral("tag"), Field::Tag}, {QStringLiteral("is"), Field::Is}, + {QStringLiteral("has"), Field::Has}, {QStringLiteral("uuid"), Field::Uuid}}; // Group 1 = modifiers, Group 2 = field, Group 3 = quoted string, Group 4 = unquoted string diff --git a/src/core/EntrySearcher.h b/src/core/EntrySearcher.h index 0134054bf..a15916fb0 100644 --- a/src/core/EntrySearcher.h +++ b/src/core/EntrySearcher.h @@ -41,6 +41,7 @@ public: Group, Tag, Is, + Has, Uuid }; diff --git a/src/core/Exporter.h b/src/core/Exporter.h deleted file mode 100644 index 1dd24b3fb..000000000 --- a/src/core/Exporter.h +++ /dev/null @@ -1,16 +0,0 @@ -#ifndef KEEPASSX_EXPORTER_H -#define KEEPASSX_EXPORTER_H - -class Database; -class Group; - -class Exporter -{ -public: - virtual Database* exportGroup(Group* group) = 0; - virtual ~Exporter() - { - } -}; - -#endif // KEEPASSX_EXPORTER_H diff --git a/src/core/FileWatcher.cpp b/src/core/FileWatcher.cpp index c919a64ef..3a3c6d83b 100644 --- a/src/core/FileWatcher.cpp +++ b/src/core/FileWatcher.cpp @@ -79,17 +79,18 @@ void FileWatcher::stop() m_fileChecksum.clear(); m_fileChecksumTimer.stop(); m_fileChangeDelayTimer.stop(); + m_paused = false; } void FileWatcher::pause() { - m_ignoreFileChange = true; + m_paused = true; m_fileChangeDelayTimer.stop(); } void FileWatcher::resume() { - m_ignoreFileChange = false; + m_paused = false; // Add a short delay to start in the next event loop if (!m_fileIgnoreDelayTimer.isActive()) { m_fileIgnoreDelayTimer.start(0); @@ -98,7 +99,7 @@ void FileWatcher::resume() bool FileWatcher::shouldIgnoreChanges() { - return m_filePath.isEmpty() || m_ignoreFileChange || m_fileIgnoreDelayTimer.isActive() + return m_filePath.isEmpty() || m_ignoreFileChange || m_paused || m_fileIgnoreDelayTimer.isActive() || m_fileChangeDelayTimer.isActive(); } @@ -116,9 +117,9 @@ void FileWatcher::checkFileChanged() // Prevent reentrance m_ignoreFileChange = true; - AsyncTask::runThenCallback([=] { return calculateChecksum(); }, + AsyncTask::runThenCallback([this] { return calculateChecksum(); }, this, - [=](QByteArray checksum) { + [this](const QByteArray& checksum) { if (checksum != m_fileChecksum) { m_fileChecksum = checksum; m_fileChangeDelayTimer.start(0); @@ -131,7 +132,7 @@ void FileWatcher::checkFileChanged() QByteArray FileWatcher::calculateChecksum() { QFile file(m_filePath); - if (file.open(QFile::ReadOnly)) { + if (!m_filePath.isEmpty() && file.open(QFile::ReadOnly)) { QCryptographicHash hash(QCryptographicHash::Sha256); if (m_fileChecksumSizeBytes > 0) { hash.addData(file.read(m_fileChecksumSizeBytes)); diff --git a/src/core/FileWatcher.h b/src/core/FileWatcher.h index 27159d17a..7a5649764 100644 --- a/src/core/FileWatcher.h +++ b/src/core/FileWatcher.h @@ -56,6 +56,7 @@ private: QTimer m_fileChecksumTimer; int m_fileChecksumSizeBytes = -1; bool m_ignoreFileChange = false; + bool m_paused = false; }; #endif // KEEPASSXC_FILEWATCHER_H diff --git a/src/core/Global.h b/src/core/Global.h index e9a4db739..9630f2f73 100644 --- a/src/core/Global.h +++ b/src/core/Global.h @@ -21,6 +21,7 @@ #define KEEPASSX_GLOBAL_H #include +#include #if defined(Q_OS_WIN) #if defined(KEEPASSX_BUILDING_CORE) @@ -42,6 +43,23 @@ #define FILE_CASE_SENSITIVE Qt::CaseSensitive #endif +#if QT_VERSION < QT_VERSION_CHECK(5, 14, 0) +// "Backport" a few things to the 'Qt' namespace as required for older Qt +// versions. +namespace Qt +{ + const QString::SplitBehavior SkipEmptyParts = QString::SkipEmptyParts; + inline QTextStream& endl(QTextStream& s) + { + return ::endl(s); + } + inline QTextStream& flush(QTextStream& s) + { + return ::flush(s); + } +} // namespace Qt +#endif + static const auto TRUE_STR = QStringLiteral("true"); static const auto FALSE_STR = QStringLiteral("false"); diff --git a/src/core/Group.cpp b/src/core/Group.cpp index cf263aa28..b7182740f 100644 --- a/src/core/Group.cpp +++ b/src/core/Group.cpp @@ -180,7 +180,7 @@ QString Group::effectiveAutoTypeSequence() const const Group* group = this; do { if (group->autoTypeEnabled() == Group::Disable) { - return QString(); + return {}; } sequence = group->defaultAutoTypeSequence(); @@ -247,6 +247,20 @@ bool Group::isEmpty() const return !hasChildren() && m_entries.isEmpty(); } +// TODO: Refactor this when KeeShare is refactored +bool Group::isShared() const +{ + auto group = this; + do { + if (group->customData()->contains("KeeShare/Reference")) { + return true; + } + group = group->m_parent; + } while (group); + + return false; +} + CustomData* Group::customData() { return m_customData; @@ -286,6 +300,21 @@ void Group::setCustomDataTriState(const QString& key, const Group::TriState& val } } +// Note that this returns an empty string both if the key is missing *or* if the key is present but value is empty. +QString Group::resolveCustomDataString(const QString& key, bool checkParent) const +{ + // If not defined, check our parent up to the root group + if (!m_customData->contains(key)) { + if (!m_parent || !checkParent) { + return QString(); + } else { + return m_parent->resolveCustomDataString(key); + } + } + + return m_customData->value(key); +} + bool Group::equals(const Group* other, CompareItemOptions options) const { if (!other) { @@ -902,7 +931,7 @@ Group* Group::findChildByName(const QString& name) */ Group* Group::clone(Entry::CloneFlags entryFlags, Group::CloneFlags groupFlags) const { - Group* clonedGroup = new Group(); + auto clonedGroup = new Group(); clonedGroup->setUpdateTimeinfo(false); diff --git a/src/core/Group.h b/src/core/Group.h index 8d5a78d49..95489bc59 100644 --- a/src/core/Group.h +++ b/src/core/Group.h @@ -39,11 +39,8 @@ public: enum MergeMode { Default, // Determine merge strategy from parent or fallback (Synchronize) - Duplicate, // lossy strategy regarding deletions, duplicate older changes in a new entry - KeepLocal, // merge history forcing local as top regardless of age - KeepRemote, // merge history forcing remote as top regardless of age KeepNewer, // merge history - Synchronize, // merge history keeping most recent as top entry and appling deletions + Synchronize, // merge history keeping most recent as top entry and applying deletions }; enum CloneFlag @@ -78,7 +75,7 @@ public: }; Group(); - ~Group(); + ~Group() override; const QUuid& uuid() const; const QString uuidToHex() const; @@ -101,10 +98,12 @@ public: bool isExpired() const; bool isRecycled() const; bool isEmpty() const; + bool isShared() const; CustomData* customData(); const CustomData* customData() const; Group::TriState resolveCustomDataTriState(const QString& key, bool checkParent = true) const; void setCustomDataTriState(const QString& key, const Group::TriState& value); + QString resolveCustomDataString(const QString& key, bool checkParent = true) const; const Group* previousParentGroup() const; QUuid previousParentGroupUuid() const; @@ -156,7 +155,6 @@ public: const QList& children() const; QList entries(); const QList& entries() const; - Entry* findEntryRecursive(const QString& text, EntryReferenceType referenceType, Group* group = nullptr); QList referencesRecursive(const Entry* entry) const; QList entriesRecursive(bool includeHistoryItems = false) const; QList groupsRecursive(bool includeSelf) const; diff --git a/src/core/InactivityTimer.cpp b/src/core/InactivityTimer.cpp index 85c58d269..501db50b5 100644 --- a/src/core/InactivityTimer.cpp +++ b/src/core/InactivityTimer.cpp @@ -20,28 +20,28 @@ #include #include +namespace +{ + // Minimum timeout is 10 seconds + constexpr int MIN_TIMEOUT = 10000; +} // namespace + InactivityTimer::InactivityTimer(QObject* parent) : QObject(parent) , m_timer(new QTimer(this)) - , m_active(false) { - m_timer->setSingleShot(true); + m_timer->setSingleShot(false); connect(m_timer, SIGNAL(timeout()), SLOT(timeout())); } -void InactivityTimer::setInactivityTimeout(int inactivityTimeout) -{ - Q_ASSERT(inactivityTimeout > 0); - - m_timer->setInterval(inactivityTimeout); -} - -void InactivityTimer::activate() +void InactivityTimer::activate(int inactivityTimeout) { if (!m_active) { qApp->installEventFilter(this); } m_active = true; + m_resetBlocked = false; + m_timer->setInterval(qMax(MIN_TIMEOUT, inactivityTimeout)); m_timer->start(); } @@ -54,12 +54,15 @@ void InactivityTimer::deactivate() bool InactivityTimer::eventFilter(QObject* watched, QEvent* event) { - const QEvent::Type type = event->type(); + const auto type = event->type(); // clang-format off - if ((type >= QEvent::MouseButtonPress && type <= QEvent::KeyRelease) - || (type >= QEvent::HoverEnter && type <= QEvent::HoverMove) - || (type == QEvent::Wheel)) { + if (!m_resetBlocked && + ((type >= QEvent::MouseButtonPress && type <= QEvent::KeyRelease) || + (type >= QEvent::HoverEnter && type <= QEvent::HoverMove) || + type == QEvent::Wheel)) { m_timer->start(); + m_resetBlocked = true; + QTimer::singleShot(500, this, [this]() { m_resetBlocked = false; }); } // clang-format on @@ -73,7 +76,7 @@ void InactivityTimer::timeout() return; } - if (m_active && !m_timer->isActive()) { + if (m_active) { emit inactivityDetected(); } diff --git a/src/core/InactivityTimer.h b/src/core/InactivityTimer.h index b9de80fb4..c19a4b776 100644 --- a/src/core/InactivityTimer.h +++ b/src/core/InactivityTimer.h @@ -29,22 +29,22 @@ class InactivityTimer : public QObject public: explicit InactivityTimer(QObject* parent = nullptr); - void setInactivityTimeout(int inactivityTimeout); - void activate(); + void activate(int inactivityTimeout); void deactivate(); signals: void inactivityDetected(); protected: - bool eventFilter(QObject* watched, QEvent* event); + bool eventFilter(QObject* watched, QEvent* event) override; private slots: void timeout(); private: QTimer* m_timer; - bool m_active; + bool m_active = false; + bool m_resetBlocked = false; QMutex m_emitMutx; }; diff --git a/src/core/Merger.cpp b/src/core/Merger.cpp index 7153ac31e..31da6e106 100644 --- a/src/core/Merger.cpp +++ b/src/core/Merger.cpp @@ -17,7 +17,9 @@ #include "Merger.h" +#include "core/Global.h" #include "core/Metadata.h" +#include "core/Tools.h" Merger::Merger(const Database* sourceDb, Database* targetDb) : m_mode(Group::Default) @@ -163,13 +165,6 @@ Merger::resolveGroupConflict(const MergeContext& context, const Group* sourceChi return changes; } -bool Merger::markOlderEntry(Entry* entry) -{ - entry->attributes()->set( - "merged", tr("older entry merged from database \"%1\"").arg(entry->group()->database()->metadata()->name())); - return true; -} - void Merger::moveEntry(Entry* entry, Group* targetGroup) { Q_ASSERT(entry); @@ -262,76 +257,6 @@ void Merger::eraseGroup(Group* group) database->setDeletedObjects(deletions); } -Merger::ChangeList -Merger::resolveEntryConflict_Duplicate(const MergeContext& context, const Entry* sourceEntry, Entry* targetEntry) -{ - ChangeList changes; - const int comparison = compare(targetEntry->timeInfo().lastModificationTime(), - sourceEntry->timeInfo().lastModificationTime(), - CompareItemIgnoreMilliseconds); - // if one entry is newer, create a clone and add it to the group - if (comparison < 0) { - Entry* clonedEntry = sourceEntry->clone(Entry::CloneNewUuid | Entry::CloneIncludeHistory); - moveEntry(clonedEntry, context.m_targetGroup); - markOlderEntry(targetEntry); - changes << tr("Adding backup for older target %1 [%2]").arg(targetEntry->title(), targetEntry->uuidToHex()); - } else if (comparison > 0) { - Entry* clonedEntry = sourceEntry->clone(Entry::CloneNewUuid | Entry::CloneIncludeHistory); - moveEntry(clonedEntry, context.m_targetGroup); - markOlderEntry(clonedEntry); - changes << tr("Adding backup for older source %1 [%2]").arg(sourceEntry->title(), sourceEntry->uuidToHex()); - } - return changes; -} - -Merger::ChangeList -Merger::resolveEntryConflict_KeepLocal(const MergeContext& context, const Entry* sourceEntry, Entry* targetEntry) -{ - Q_UNUSED(context); - ChangeList changes; - const int comparison = compare(targetEntry->timeInfo().lastModificationTime(), - sourceEntry->timeInfo().lastModificationTime(), - CompareItemIgnoreMilliseconds); - if (comparison < 0) { - // we need to make our older entry "newer" than the new entry - therefore - // we just create a new history entry without any changes - this preserves - // the old state before merging the new state and updates the timestamp - // the merge takes care, that the newer entry is sorted inbetween both entries - // this type of merge changes the database timestamp since reapplying the - // old entry is an active change of the database! - changes << tr("Reapplying older target entry on top of newer source %1 [%2]") - .arg(targetEntry->title(), targetEntry->uuidToHex()); - Entry* agedTargetEntry = targetEntry->clone(Entry::CloneNoFlags); - targetEntry->addHistoryItem(agedTargetEntry); - } - return changes; -} - -Merger::ChangeList -Merger::resolveEntryConflict_KeepRemote(const MergeContext& context, const Entry* sourceEntry, Entry* targetEntry) -{ - Q_UNUSED(context); - ChangeList changes; - const int comparison = compare(targetEntry->timeInfo().lastModificationTime(), - sourceEntry->timeInfo().lastModificationTime(), - CompareItemIgnoreMilliseconds); - if (comparison > 0) { - // we need to make our older entry "newer" than the new entry - therefore - // we just create a new history entry without any changes - this preserves - // the old state before merging the new state and updates the timestamp - // the merge takes care, that the newer entry is sorted inbetween both entries - // this type of merge changes the database timestamp since reapplying the - // old entry is an active change of the database! - changes << tr("Reapplying older source entry on top of newer target %1 [%2]") - .arg(targetEntry->title(), targetEntry->uuidToHex()); - targetEntry->beginUpdate(); - targetEntry->copyDataFrom(sourceEntry); - targetEntry->endUpdate(); - // History item is created by endUpdate since we should have changes - } - return changes; -} - Merger::ChangeList Merger::resolveEntryConflict_MergeHistories(const MergeContext& context, const Entry* sourceEntry, Entry* targetEntry, @@ -372,38 +297,12 @@ Merger::ChangeList Merger::resolveEntryConflict_MergeHistories(const MergeContex Merger::ChangeList Merger::resolveEntryConflict(const MergeContext& context, const Entry* sourceEntry, Entry* targetEntry) { - ChangeList changes; // We need to cut off the milliseconds since the persistent format only supports times down to seconds // so when we import data from a remote source, it may represent the (or even some msec newer) data // which may be discarded due to higher runtime precision Group::MergeMode mergeMode = m_mode == Group::Default ? context.m_targetGroup->mergeMode() : m_mode; - switch (mergeMode) { - case Group::Duplicate: - changes << resolveEntryConflict_Duplicate(context, sourceEntry, targetEntry); - break; - - case Group::KeepLocal: - changes << resolveEntryConflict_KeepLocal(context, sourceEntry, targetEntry); - changes << resolveEntryConflict_MergeHistories(context, sourceEntry, targetEntry, mergeMode); - break; - - case Group::KeepRemote: - changes << resolveEntryConflict_KeepRemote(context, sourceEntry, targetEntry); - changes << resolveEntryConflict_MergeHistories(context, sourceEntry, targetEntry, mergeMode); - break; - - case Group::Synchronize: - case Group::KeepNewer: - // nothing special to do since resolveEntryConflictMergeHistories takes care to use the newest entry - changes << resolveEntryConflict_MergeHistories(context, sourceEntry, targetEntry, mergeMode); - break; - - default: - // do nothing - break; - } - return changes; + return resolveEntryConflict_MergeHistories(context, sourceEntry, targetEntry, mergeMode); } bool Merger::mergeHistory(const Entry* sourceEntry, @@ -417,8 +316,8 @@ bool Merger::mergeHistory(const Entry* sourceEntry, const int comparison = compare(sourceEntry->timeInfo().lastModificationTime(), targetEntry->timeInfo().lastModificationTime(), CompareItemIgnoreMilliseconds); - const bool preferLocal = mergeMethod == Group::KeepLocal || comparison < 0; - const bool preferRemote = mergeMethod == Group::KeepRemote || comparison > 0; + const bool preferLocal = comparison < 0; + const bool preferRemote = comparison > 0; QMap merged; for (Entry* historyItem : targetHistoryItems) { @@ -576,7 +475,7 @@ Merger::ChangeList Merger::mergeDeletions(const MergeContext& context) while (!groups.isEmpty()) { auto* group = groups.takeFirst(); - if (!(group->children().toSet() & groups.toSet()).isEmpty()) { + if (Tools::asSet(group->children()).intersects(Tools::asSet(groups))) { // we need to finish all children before we are able to determine if the group can be removed groups << group; continue; diff --git a/src/core/Merger.h b/src/core/Merger.h index b46c296ea..9669e89e3 100644 --- a/src/core/Merger.h +++ b/src/core/Merger.h @@ -50,22 +50,15 @@ private: ChangeList mergeGroup(const MergeContext& context); ChangeList mergeDeletions(const MergeContext& context); ChangeList mergeMetadata(const MergeContext& context); - bool markOlderEntry(Entry* entry); bool mergeHistory(const Entry* sourceEntry, Entry* targetEntry, Group::MergeMode mergeMethod, const int maxItems); void moveEntry(Entry* entry, Group* targetGroup); void moveGroup(Group* group, Group* targetGroup); - // remove an entry without a trace in the deletedObjects - needed for elemination cloned entries + // remove an entry without a trace in the deletedObjects - needed for elimination of cloned entries void eraseEntry(Entry* entry); - // remove an entry without a trace in the deletedObjects - needed for elemination cloned entries + // remove an entry without a trace in the deletedObjects - needed for elimination of cloned entries void eraseGroup(Group* group); ChangeList resolveEntryConflict(const MergeContext& context, const Entry* existingEntry, Entry* otherEntry); ChangeList resolveGroupConflict(const MergeContext& context, const Group* existingGroup, Group* otherGroup); - Merger::ChangeList - resolveEntryConflict_Duplicate(const MergeContext& context, const Entry* sourceEntry, Entry* targetEntry); - Merger::ChangeList - resolveEntryConflict_KeepLocal(const MergeContext& context, const Entry* sourceEntry, Entry* targetEntry); - Merger::ChangeList - resolveEntryConflict_KeepRemote(const MergeContext& context, const Entry* sourceEntry, Entry* targetEntry); Merger::ChangeList resolveEntryConflict_MergeHistories(const MergeContext& context, const Entry* sourceEntry, Entry* targetEntry, diff --git a/src/core/Metadata.cpp b/src/core/Metadata.cpp index c3d4b8e1b..8e714e0f2 100644 --- a/src/core/Metadata.cpp +++ b/src/core/Metadata.cpp @@ -279,7 +279,7 @@ int Metadata::autosaveDelayMin() const // data is not set yet, use default return Metadata::DefaultAutosaveDelayMin; } - bool ok; // check for QString to int op failuer + bool ok; // check for QString to int op failure int autosaveDelayMin = autosaveDelayMinStr.toInt(&ok); Q_ASSERT(ok); return autosaveDelayMin; diff --git a/src/core/PassphraseGenerator.cpp b/src/core/PassphraseGenerator.cpp index ef1d867e2..07e7a31bf 100644 --- a/src/core/PassphraseGenerator.cpp +++ b/src/core/PassphraseGenerator.cpp @@ -18,12 +18,14 @@ #include "PassphraseGenerator.h" #include +#include #include #include #include "core/Resources.h" #include "crypto/Random.h" +const int PassphraseGenerator::DefaultWordCount = 7; const char* PassphraseGenerator::DefaultSeparator = " "; const char* PassphraseGenerator::DefaultWordList = "eff_large.wordlist"; @@ -60,14 +62,17 @@ void PassphraseGenerator::setWordCase(PassphraseWordCase wordCase) void PassphraseGenerator::setWordList(const QString& path) { m_wordlist.clear(); + // Initially load wordlist into a set to avoid duplicates + QSet wordset; QFile file(path); if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { - qWarning("Couldn't load passphrase wordlist."); + qWarning("Couldn't load passphrase wordlist: %s", qPrintable(path)); return; } QTextStream in(&file); + in.setCodec("UTF-8"); QString line = in.readLine(); bool isSigned = line.startsWith("-----BEGIN PGP SIGNED MESSAGE-----"); if (isSigned) { @@ -87,14 +92,15 @@ void PassphraseGenerator::setWordList(const QString& path) line = line.trimmed(); line.replace(rx, "\\2"); if (!line.isEmpty()) { - m_wordlist.append(line); + wordset.insert(line); } line = in.readLine(); } - if (m_wordlist.size() < 4000) { - qWarning("Wordlist too short!"); - return; + m_wordlist = wordset.toList(); + + if (!isWordListValid()) { + qWarning("Wordlist is less than minimum acceptable size: %s", qPrintable(path)); } } @@ -111,18 +117,15 @@ void PassphraseGenerator::setWordSeparator(const QString& separator) QString PassphraseGenerator::generatePassphrase() const { - QString tmpWord; - Q_ASSERT(isValid()); - - // In case there was an error loading the wordlist - if (m_wordlist.length() == 0) { - return QString(); + if (m_wordlist.isEmpty()) { + return {}; } QStringList words; + int randomIndex = randomGen()->randomUInt(static_cast(m_wordCount)); for (int i = 0; i < m_wordCount; ++i) { - int wordIndex = randomGen()->randomUInt(static_cast(m_wordlist.length())); - tmpWord = m_wordlist.at(wordIndex); + int wordIndex = randomGen()->randomUInt(static_cast(m_wordlist.size())); + auto tmpWord = m_wordlist.at(wordIndex); // convert case switch (m_wordCase) { @@ -132,8 +135,10 @@ QString PassphraseGenerator::generatePassphrase() const case TITLECASE: tmpWord = tmpWord.replace(0, 1, tmpWord.left(1).toUpper()); break; + case MIXEDCASE: + tmpWord = i == randomIndex ? tmpWord.toUpper() : tmpWord.toLower(); + break; case LOWERCASE: - default: tmpWord = tmpWord.toLower(); break; } @@ -143,11 +148,7 @@ QString PassphraseGenerator::generatePassphrase() const return words.join(m_separator); } -bool PassphraseGenerator::isValid() const +bool PassphraseGenerator::isWordListValid() const { - if (m_wordCount == 0) { - return false; - } - - return m_wordlist.size() >= 1000; + return m_wordlist.size() >= m_minWordListSize; } diff --git a/src/core/PassphraseGenerator.h b/src/core/PassphraseGenerator.h index bb282f59b..5d404c990 100644 --- a/src/core/PassphraseGenerator.h +++ b/src/core/PassphraseGenerator.h @@ -18,7 +18,7 @@ #ifndef KEEPASSX_PASSPHRASEGENERATOR_H #define KEEPASSX_PASSPHRASEGENERATOR_H -#include +#include class PassphraseGenerator { @@ -30,7 +30,8 @@ public: { LOWERCASE, UPPERCASE, - TITLECASE + TITLECASE, + MIXEDCASE }; double estimateEntropy(int wordCount = 0); @@ -39,19 +40,22 @@ public: void setWordCase(PassphraseWordCase wordCase); void setDefaultWordList(); void setWordSeparator(const QString& separator); - bool isValid() const; + bool isWordListValid() const; QString generatePassphrase() const; - static constexpr int DefaultWordCount = 7; + static const int DefaultWordCount; static const char* DefaultSeparator; static const char* DefaultWordList; private: int m_wordCount; + int m_minWordListSize = 1296; PassphraseWordCase m_wordCase; QString m_separator; - QVector m_wordlist; + QList m_wordlist; + + friend class TestPassphraseGenerator; }; #endif // KEEPASSX_PASSPHRASEGENERATOR_H diff --git a/src/core/PasswordHealth.cpp b/src/core/PasswordHealth.cpp index 3225affb3..3a2e5571d 100644 --- a/src/core/PasswordHealth.cpp +++ b/src/core/PasswordHealth.cpp @@ -17,6 +17,7 @@ #include +#include "Clock.h" #include "Group.h" #include "PasswordHealth.h" #include "zxcvbn.h" @@ -171,8 +172,8 @@ QSharedPointer HealthChecker::evaluate(const Entry* entry) const if (entry->isExpired()) { health->setScore(0); health->addScoreReason(QObject::tr("Password has expired")); - health->addScoreDetails(QObject::tr("Password expiry was %1") - .arg(entry->timeInfo().expiryTime().toString(Qt::DefaultLocaleShortDate))); + health->addScoreDetails( + QObject::tr("Password expiry was %1").arg(Clock::toString(entry->timeInfo().expiryTime()))); } else if (entry->timeInfo().expires()) { const int days = QDateTime::currentDateTime().daysTo(entry->timeInfo().expiryTime()); if (days <= 30) { @@ -186,8 +187,8 @@ QSharedPointer HealthChecker::evaluate(const Entry* entry) const } health->adjustScore((30 - days) * -2); - health->addScoreDetails(QObject::tr("Password expires on %1") - .arg(entry->timeInfo().expiryTime().toString(Qt::DefaultLocaleShortDate))); + health->addScoreDetails( + QObject::tr("Password expires on %1").arg(Clock::toString(entry->timeInfo().expiryTime()))); if (days <= 2) { health->addScoreReason(QObject::tr("Password is about to expire")); } else if (days <= 10) { diff --git a/src/core/SignalMultiplexer.cpp b/src/core/SignalMultiplexer.cpp index d1ed89e30..99f7fab15 100644 --- a/src/core/SignalMultiplexer.cpp +++ b/src/core/SignalMultiplexer.cpp @@ -19,9 +19,7 @@ #include "core/Global.h" -SignalMultiplexer::SignalMultiplexer() -{ -} +SignalMultiplexer::SignalMultiplexer() = default; SignalMultiplexer::~SignalMultiplexer() { diff --git a/src/core/TimeDelta.cpp b/src/core/TimeDelta.cpp index 0037396f6..94cea03c8 100644 --- a/src/core/TimeDelta.cpp +++ b/src/core/TimeDelta.cpp @@ -29,22 +29,22 @@ QDateTime operator+(const QDateTime& dateTime, const TimeDelta& delta) TimeDelta TimeDelta::fromHours(int hours) { - return TimeDelta(hours, 0, 0, 0); + return {hours, 0, 0, 0}; } TimeDelta TimeDelta::fromDays(int days) { - return TimeDelta(0, days, 0, 0); + return {0, days, 0, 0}; } TimeDelta TimeDelta::fromMonths(int months) { - return TimeDelta(0, 0, months, 0); + return {0, 0, months, 0}; } TimeDelta TimeDelta::fromYears(int years) { - return TimeDelta(0, 0, 0, years); + return {0, 0, 0, years}; } TimeDelta::TimeDelta() diff --git a/src/core/Tools.cpp b/src/core/Tools.cpp index aa83305c4..814233941 100644 --- a/src/core/Tools.cpp +++ b/src/core/Tools.cpp @@ -35,6 +35,7 @@ #include #include #include +#include #include #include #include @@ -77,7 +78,6 @@ namespace Tools #endif debugInfo.append("\n"); -#if QT_VERSION >= QT_VERSION_CHECK(5, 4, 0) debugInfo.append(QObject::tr("Operating system: %1\nCPU architecture: %2\nKernel: %3 %4") .arg(QSysInfo::prettyProductName(), QSysInfo::currentCpuArchitecture(), @@ -85,7 +85,6 @@ namespace Tools QSysInfo::kernelVersion())); debugInfo.append("\n\n"); -#endif QString extensions; #ifdef WITH_XC_AUTOTYPE @@ -126,10 +125,7 @@ namespace Tools constexpr auto kibibyte = 1024; double size = bytes; - QStringList units = QStringList() << "B" - << "KiB" - << "MiB" - << "GiB"; + QStringList units = QStringList() << "B" << "KiB" << "MiB" << "GiB"; int i = 0; int maxI = units.size() - 1; @@ -451,34 +447,89 @@ namespace Tools QString substituteBackupFilePath(QString pattern, const QString& databasePath) { - // Fail if substitution fails if (databasePath.isEmpty()) { return {}; } - // Replace backup pattern - QFileInfo dbFileInfo(databasePath); - QString baseName = dbFileInfo.completeBaseName(); + const QString baseName = QFileInfo{databasePath}.completeBaseName(); - pattern.replace(QString("{DB_FILENAME}"), baseName); + pattern.replace(QStringLiteral("{DB_FILENAME}"), baseName); - auto re = QRegularExpression(R"(\{TIME(?::([^\\]*))?\})"); + const QDateTime now = Clock::currentDateTime(); + + const QRegularExpression re(R"(\{TIME(?::([^\\{}]*))?\})"); auto match = re.match(pattern); while (match.hasMatch()) { - // Extract time format specifier - auto formatSpecifier = QString("dd_MM_yyyy_hh-mm-ss"); + // Extract time format specifier, or use default value if absent + QString formatSpecifier = "dd_MM_yyyy_hh-mm-ss"; if (!match.captured(1).isEmpty()) { formatSpecifier = match.captured(1); } - auto replacement = Clock::currentDateTime().toString(formatSpecifier); + const auto replacement = now.toString(formatSpecifier); pattern.replace(match.capturedStart(), match.capturedLength(), replacement); match = re.match(pattern); } // Replace escaped braces - pattern.replace("\\{", "{"); - pattern.replace("\\}", "}"); + pattern.replace(QStringLiteral("\\{"), QStringLiteral("{")); + pattern.replace(QStringLiteral("\\}"), QStringLiteral("}")); return pattern; } + + MimeType toMimeType(const QString& mimeName) + { + const static QStringList TextFormats = {"text/", + "application/json", + "application/xml", + "application/soap+xml", + "application/x-yaml", + "application/protobuf", + "application/x-zerosize"}; + const static QStringList HtmlFormats = {"text/html"}; + const static QStringList MarkdownFormats = {"text/markdown"}; + const static QStringList ImageFormats = {"image/"}; + + static auto isCompatible = [](const QString& format, const QStringList& list) { + return std::any_of( + list.cbegin(), list.cend(), [&format](const auto& item) { return format.startsWith(item); }); + }; + + if (isCompatible(mimeName, ImageFormats)) { + return MimeType::Image; + } + + if (isCompatible(mimeName, TextFormats)) { + if (isCompatible(mimeName, HtmlFormats)) { + return MimeType::Html; + } else if (isCompatible(mimeName, MarkdownFormats)) { + return MimeType::Markdown; + } + + return MimeType::PlainText; + } + + return MimeType::Unknown; + } + + MimeType getMimeType(const QByteArray& data) + { + QMimeDatabase mimeDb; + const auto mime = mimeDb.mimeTypeForData(data); + return toMimeType(mime.name()); + } + + MimeType getMimeType(const QFileInfo& fileInfo) + { + QMimeDatabase mimeDb; + const auto mime = mimeDb.mimeTypeForFile(fileInfo); + return toMimeType(mime.name()); + } + + bool isTextMimeType(MimeType mimeType) + { + return mimeType == Tools::MimeType::PlainText || mimeType == Tools::MimeType::Html + || mimeType == Tools::MimeType::Markdown; + } + } // namespace Tools diff --git a/src/core/Tools.h b/src/core/Tools.h index 61d93ffbd..ee5ef612e 100644 --- a/src/core/Tools.h +++ b/src/core/Tools.h @@ -22,8 +22,10 @@ #include "core/Global.h" #include +#include #include #include +#include class QIODevice; class QRegularExpression; @@ -47,6 +49,15 @@ namespace Tools QProcessEnvironment environment = QProcessEnvironment::systemEnvironment()); QString cleanFilename(QString filename); + template QSet asSet(const QList& a) + { +#if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0) + return QSet(a.begin(), a.end()); +#else + return QSet::fromList(a); +#endif + } + /** * Escapes all characters in regex such that they do not receive any special treatment when used * in a regular expression. Essentially, this function escapes any characters not in a-zA-Z0-9. @@ -88,20 +99,6 @@ namespace Tools } } - inline int qtRuntimeVersion() - { - // Cache the result since the Qt version can't change during - // the execution, computing it once will be enough - const static int version = []() { - const auto sq = QString::fromLatin1(qVersion()); - return (sq.section(QChar::fromLatin1('.'), 0, 0).toInt() << 16) - + (sq.section(QChar::fromLatin1('.'), 1, 1).toInt() << 8) - + (sq.section(QChar::fromLatin1('.'), 2, 2).toInt()); - }(); - - return version; - } - // Checks if all values are found inside the list. Returns a list of values not found. template QList getMissingValuesFromList(const QList& list, const QList& required) { @@ -118,6 +115,21 @@ namespace Tools QVariantMap qo2qvm(const QObject* object, const QStringList& ignoredProperties = {"objectName"}); QString substituteBackupFilePath(QString pattern, const QString& databasePath); + + enum class MimeType : uint8_t + { + Image, + PlainText, + Html, + Markdown, + Unknown + }; + + MimeType toMimeType(const QString& mimeName); + MimeType getMimeType(const QByteArray& data); + MimeType getMimeType(const QFileInfo& fileInfo); + bool isTextMimeType(MimeType mimeType); + } // namespace Tools #endif // KEEPASSX_TOOLS_H diff --git a/src/core/Totp.cpp b/src/core/Totp.cpp index f55312a9d..ed15a9fb8 100644 --- a/src/core/Totp.cpp +++ b/src/core/Totp.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2017 Weslly Honorato <weslly@protonmail.com> + * Copyright (C) 2017 Weslly Honorato * Copyright (C) 2017 KeePassXC Team * * This program is free software: you can redistribute it and/or modify @@ -36,10 +36,11 @@ static QList totpEncoders{ static Totp::Algorithm getHashTypeByName(const QString& name) { - if (name.compare(QString("SHA512"), Qt::CaseInsensitive) == 0) { + auto nameUpper = name.toUpper(); + if (nameUpper == "SHA512" || nameUpper == "HMAC-SHA-512") { return Totp::Algorithm::Sha512; } - if (name.compare(QString("SHA256"), Qt::CaseInsensitive) == 0) { + if (nameUpper == "SHA256" || nameUpper == "HMAC-SHA-256") { return Totp::Algorithm::Sha256; } return Totp::Algorithm::Sha1; @@ -49,14 +50,38 @@ static QString getNameForHashType(const Totp::Algorithm hashType) { switch (hashType) { case Totp::Algorithm::Sha512: - return QString("SHA512"); + return "SHA512"; case Totp::Algorithm::Sha256: - return QString("SHA256"); + return "SHA256"; default: - return QString("SHA1"); + return "SHA1"; } } +QSharedPointer +Totp::fromKeePass2Totp(const QString& secret, const QString& algorithm, const QString& length, const QString& period) +{ + // Must have at least a secret to continue + if (secret.isEmpty()) { + return {}; + } + + // Create default settings + auto settings = createSettings(secret); + + if (!algorithm.isEmpty()) { + settings->algorithm = getHashTypeByName(algorithm); + } + if (!length.isEmpty()) { + settings->digits = length.toUInt(); + } + if (!period.isEmpty()) { + settings->step = period.toUInt(); + } + + return settings; +} + QSharedPointer Totp::parseSettings(const QString& rawSettings, const QString& key) { // Early out if both strings are empty @@ -65,7 +90,7 @@ QSharedPointer Totp::parseSettings(const QString& rawSettings, c } // Create default settings - auto settings = createSettings(key, DEFAULT_DIGITS, DEFAULT_STEP); + auto settings = createSettings(key); QUrl url(rawSettings); if (url.isValid() && url.scheme() == "otpauth") { @@ -113,6 +138,7 @@ QSharedPointer Totp::parseSettings(const QString& rawSettings, c if (vars[1] == STEAM_SHORTNAME) { // Explicit steam encoder settings->encoder = steamEncoder(); + settings->digits = STEAM_DIGITS; } else { // Extract step and digits settings->step = vars[0].toUInt(); @@ -126,13 +152,6 @@ QSharedPointer Totp::parseSettings(const QString& rawSettings, c settings->digits = qBound(1u, settings->digits, 10u); settings->step = qBound(1u, settings->step, 86400u); - // Detect custom settings, used by setup GUI - if (settings->encoder.shortName.isEmpty() - && (settings->digits != DEFAULT_DIGITS || settings->step != DEFAULT_STEP - || settings->algorithm != DEFAULT_ALGORITHM)) { - settings->custom = true; - } - return settings; } @@ -143,9 +162,8 @@ QSharedPointer Totp::createSettings(const QString& key, const QString& encoderShortName, const Totp::Algorithm algorithm) { - bool isCustom = digits != DEFAULT_DIGITS || step != DEFAULT_STEP || algorithm != DEFAULT_ALGORITHM; return QSharedPointer( - new Totp::Settings{format, getEncoderByShortName(encoderShortName), algorithm, key, isCustom, digits, step}); + new Totp::Settings{format, getEncoderByShortName(encoderShortName), algorithm, key, digits, step}); } QString Totp::writeSettings(const QSharedPointer& settings, @@ -192,16 +210,37 @@ QString Totp::writeSettings(const QSharedPointer& settings, } } -QString Totp::generateTotp(const QSharedPointer& settings, const quint64 time) +QString Totp::checkValidSettings(const QSharedPointer& settings) { - Q_ASSERT(!settings.isNull()); if (settings.isNull()) { return QObject::tr("Invalid Settings", "TOTP"); } + QVariant secret = Base32::decode(Base32::sanitizeInput(settings->key.toLatin1())); + if (secret.isNull()) { + return QObject::tr("Invalid Key", "TOTP"); + } + if (settings->step == 0) { + return QObject::tr("Invalid Step", "TOTP"); + } + if (settings->digits == 0) { + return QObject::tr("Invalid Digits", "TOTP"); + } + return {}; +} + +QString Totp::generateTotp(const QSharedPointer& settings, bool* isValid, const quint64 time) +{ + auto error = checkValidSettings(settings); + if (!error.isEmpty()) { + if (isValid) { + *isValid = false; + } + return error; + } const Encoder& encoder = settings->encoder; - uint step = settings->custom ? settings->step : encoder.step; - uint digits = settings->custom ? settings->digits : encoder.digits; + uint step = settings->step; + uint digits = settings->digits; quint64 current; if (time == 0) { @@ -211,9 +250,6 @@ QString Totp::generateTotp(const QSharedPointer& settings, const } QVariant secret = Base32::decode(Base32::sanitizeInput(settings->key.toLatin1())); - if (secret.isNull()) { - return QObject::tr("Invalid Key", "TOTP"); - } QCryptographicHash::Algorithm cryptoHash; switch (settings->algorithm) { @@ -256,6 +292,9 @@ QString Totp::generateTotp(const QSharedPointer& settings, const retval[pos] = encoder.alphabet[int(password % encoder.alphabet.size())]; password /= encoder.alphabet.size(); } + if (isValid) { + *isValid = true; + } return retval; } @@ -277,6 +316,13 @@ QList> Totp::supportedAlgorithms() return algorithms; } +bool Totp::hasCustomSettings(const QSharedPointer& settings) +{ + return settings + && (settings->digits != DEFAULT_DIGITS || settings->step != DEFAULT_STEP + || settings->algorithm != DEFAULT_ALGORITHM); +} + Totp::Encoder& Totp::defaultEncoder() { // The first encoder is always the default diff --git a/src/core/Totp.h b/src/core/Totp.h index c34ac164d..da857aef2 100644 --- a/src/core/Totp.h +++ b/src/core/Totp.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2017 Weslly Honorato <weslly@protonmail.com> + * Copyright (C) 2017 Weslly Honorato * Copyright (C) 2017 KeePassXC Team * * This program is free software: you can redistribute it and/or modify @@ -56,7 +56,6 @@ namespace Totp Totp::Encoder encoder; Totp::Algorithm algorithm; QString key; - bool custom; uint digits; uint step; }; @@ -72,10 +71,19 @@ namespace Totp static const QString ATTRIBUTE_SEED = "TOTP Seed"; static const QString ATTRIBUTE_SETTINGS = "TOTP Settings"; + // Support for KeePass2 TOTP + static const QString KP2_TOTP_SECRET = "TimeOtp-Secret-Base32"; + static const QString KP2_TOTP_ALGORITHM = "TimeOtp-Algorithm"; + static const QString KP2_TOTP_LENGTH = "TimeOtp-Length"; + static const QString KP2_TOTP_PERIOD = "TimeOtp-Period"; + + QSharedPointer + fromKeePass2Totp(const QString& secret, const QString& algorithm, const QString& length, const QString& period); + QSharedPointer parseSettings(const QString& rawSettings, const QString& key = {}); QSharedPointer createSettings(const QString& key, - const uint digits, - const uint step, + const uint digits = DEFAULT_DIGITS, + const uint step = DEFAULT_STEP, const Totp::StorageFormat format = DEFAULT_FORMAT, const QString& encoderShortName = {}, const Totp::Algorithm algorithm = DEFAULT_ALGORITHM); @@ -83,8 +91,12 @@ namespace Totp const QString& title = {}, const QString& username = {}, bool forceOtp = false); + // Returns an empty string if settings are valid, otherwise an error message is supplied + QString checkValidSettings(const QSharedPointer& settings); + QString + generateTotp(const QSharedPointer& settings, bool* isValid = nullptr, const quint64 time = 0ull); - QString generateTotp(const QSharedPointer& settings, const quint64 time = 0ull); + bool hasCustomSettings(const QSharedPointer& settings); QList> supportedEncoders(); QList> supportedAlgorithms(); diff --git a/src/crypto/CryptoHash.cpp b/src/crypto/CryptoHash.cpp index 5177bb86f..a1dc6595e 100644 --- a/src/crypto/CryptoHash.cpp +++ b/src/crypto/CryptoHash.cpp @@ -106,7 +106,7 @@ QByteArray CryptoHash::result() const } else if (d->hashFunction) { result = d->hashFunction->final(); } - return QByteArray(reinterpret_cast(result.data()), result.size()); + return {reinterpret_cast(result.data()), int(result.size())}; } QByteArray CryptoHash::hash(const QByteArray& data, Algorithm algo) diff --git a/src/crypto/SymmetricCipher.cpp b/src/crypto/SymmetricCipher.cpp index 1253763bc..33e61aa4f 100644 --- a/src/crypto/SymmetricCipher.cpp +++ b/src/crypto/SymmetricCipher.cpp @@ -34,7 +34,11 @@ bool SymmetricCipher::init(Mode mode, Direction direction, const QByteArray& key try { auto botanMode = modeToString(mode); auto botanDirection = +#ifdef WITH_XC_BOTAN3 + (direction == SymmetricCipher::Encrypt ? Botan::Cipher_Dir::Encryption : Botan::Cipher_Dir::Decryption); +#else (direction == SymmetricCipher::Encrypt ? Botan::Cipher_Dir::ENCRYPTION : Botan::Cipher_Dir::DECRYPTION); +#endif auto cipher = Botan::Cipher_Mode::create_or_throw(botanMode.toStdString(), botanDirection); m_cipher.reset(cipher.release()); @@ -59,15 +63,15 @@ bool SymmetricCipher::init(Mode mode, Direction direction, const QByteArray& key return true; } -bool SymmetricCipher::isInitalized() const +bool SymmetricCipher::isInitialized() const { return m_cipher; } bool SymmetricCipher::process(char* data, int len) { - Q_ASSERT(isInitalized()); - if (!isInitalized()) { + Q_ASSERT(isInitialized()); + if (!isInitialized()) { m_error = QObject::tr("Cipher not initialized prior to use."); return false; } @@ -93,8 +97,8 @@ bool SymmetricCipher::process(QByteArray& data) bool SymmetricCipher::finish(QByteArray& data) { - Q_ASSERT(isInitalized()); - if (!isInitalized()) { + Q_ASSERT(isInitialized()); + if (!isInitialized()) { m_error = QObject::tr("Cipher not initialized prior to use."); return false; } @@ -117,7 +121,7 @@ bool SymmetricCipher::finish(QByteArray& data) void SymmetricCipher::reset() { m_error.clear(); - if (isInitalized()) { + if (isInitialized()) { m_cipher.reset(); } } diff --git a/src/crypto/SymmetricCipher.h b/src/crypto/SymmetricCipher.h index e18f623f3..224e8baa9 100644 --- a/src/crypto/SymmetricCipher.h +++ b/src/crypto/SymmetricCipher.h @@ -52,7 +52,7 @@ public: explicit SymmetricCipher() = default; ~SymmetricCipher() = default; - bool isInitalized() const; + bool isInitialized() const; Q_REQUIRED_RESULT bool init(Mode mode, Direction direction, const QByteArray& key, const QByteArray& iv); Q_REQUIRED_RESULT bool process(char* data, int len); Q_REQUIRED_RESULT bool process(QByteArray& data); diff --git a/src/crypto/kdf/Argon2Kdf.cpp b/src/crypto/kdf/Argon2Kdf.cpp index fe2d5aa69..f7b028ffe 100644 --- a/src/crypto/kdf/Argon2Kdf.cpp +++ b/src/crypto/kdf/Argon2Kdf.cpp @@ -33,11 +33,11 @@ */ Argon2Kdf::Argon2Kdf(Type type) : Kdf::Kdf(type == Type::Argon2d ? KeePass2::KDF_ARGON2D : KeePass2::KDF_ARGON2ID) - , m_version(0x13) - , m_memory(1 << 16) - , m_parallelism(static_cast(QThread::idealThreadCount())) + , m_version(ARGON2_DEFAULT_VERSION) + , m_memory(ARGON2_DEFAULT_MEMORY) + , m_parallelism(qMin(QThread::idealThreadCount(), ARGON2_DEFAULT_PARALLELISM)) { - m_rounds = 10; + m_rounds = ARGON2_DEFAULT_ROUNDS; } quint32 Argon2Kdf::version() const @@ -52,7 +52,7 @@ bool Argon2Kdf::setVersion(quint32 version) m_version = version; return true; } - m_version = 0x13; + m_version = ARGON2_DEFAULT_VERSION; return false; } @@ -73,7 +73,7 @@ bool Argon2Kdf::setMemory(quint64 kibibytes) m_memory = kibibytes; return true; } - m_memory = 16; + m_memory = ARGON2_DEFAULT_MEMORY; return false; } @@ -89,7 +89,7 @@ bool Argon2Kdf::setParallelism(quint32 threads) m_parallelism = threads; return true; } - m_parallelism = 1; + m_parallelism = ARGON2_DEFAULT_PARALLELISM; return false; } diff --git a/src/crypto/kdf/Argon2Kdf.h b/src/crypto/kdf/Argon2Kdf.h index b5881b45b..c56e5f9a2 100644 --- a/src/crypto/kdf/Argon2Kdf.h +++ b/src/crypto/kdf/Argon2Kdf.h @@ -20,6 +20,11 @@ #include "Kdf.h" +constexpr auto ARGON2_DEFAULT_VERSION = 0x13; +constexpr auto ARGON2_DEFAULT_ROUNDS = 10; +constexpr auto ARGON2_DEFAULT_MEMORY = 1 << 16; +constexpr auto ARGON2_DEFAULT_PARALLELISM = 4; + class Argon2Kdf : public Kdf { public: @@ -47,6 +52,15 @@ public: int benchmark(int msec) const override; + static quint64 toMebibytes(quint64 kibibytes) + { + return kibibytes >> 10; + } + static quint64 toKibibytes(quint64 mebibits) + { + return mebibits << 10; + } + quint32 m_version; quint64 m_memory; quint32 m_parallelism; diff --git a/src/fdosecrets/CMakeLists.txt b/src/fdosecrets/CMakeLists.txt index ecdac8dc6..7489debef 100644 --- a/src/fdosecrets/CMakeLists.txt +++ b/src/fdosecrets/CMakeLists.txt @@ -9,7 +9,6 @@ if(WITH_XC_FDOSECRETS) widgets/RowButtonHelper.cpp # per database settings page - DatabaseSettingsPageFdoSecrets.cpp widgets/DatabaseSettingsWidgetFdoSecrets.cpp # prompt dialog diff --git a/src/fdosecrets/DatabaseSettingsPageFdoSecrets.cpp b/src/fdosecrets/DatabaseSettingsPageFdoSecrets.cpp deleted file mode 100644 index 60528a798..000000000 --- a/src/fdosecrets/DatabaseSettingsPageFdoSecrets.cpp +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright (C) 2019 Aetf - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 2 or (at your option) - * version 3 of the License. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include "DatabaseSettingsPageFdoSecrets.h" - -#include "fdosecrets/widgets/DatabaseSettingsWidgetFdoSecrets.h" - -#include "gui/Icons.h" - -QString DatabaseSettingsPageFdoSecrets::name() -{ - return QObject::tr("Secret Service Integration"); -} - -QIcon DatabaseSettingsPageFdoSecrets::icon() -{ - return icons()->icon(QStringLiteral("freedesktop")); -} - -QWidget* DatabaseSettingsPageFdoSecrets::createWidget() -{ - return new DatabaseSettingsWidgetFdoSecrets; -} - -void DatabaseSettingsPageFdoSecrets::loadSettings(QWidget* widget, QSharedPointer db) -{ - auto settingsWidget = qobject_cast(widget); - settingsWidget->loadSettings(db); -} - -void DatabaseSettingsPageFdoSecrets::saveSettings(QWidget* widget) -{ - auto settingsWidget = qobject_cast(widget); - settingsWidget->saveSettings(); -} diff --git a/src/fdosecrets/dbus/DBusMgr.cpp b/src/fdosecrets/dbus/DBusMgr.cpp index 1a4b2b73c..3765e6f09 100644 --- a/src/fdosecrets/dbus/DBusMgr.cpp +++ b/src/fdosecrets/dbus/DBusMgr.cpp @@ -26,6 +26,11 @@ #include "core/Entry.h" #include "core/Tools.h" +#ifdef __FreeBSD__ +#include +#include +#endif + namespace FdoSecrets { static const auto IntrospectionService = R"xml( @@ -175,7 +180,18 @@ namespace FdoSecrets // The /proc/pid/exe link is more reliable than /proc/pid/cmdline // It's still weak and if the application does a prctl(PR_SET_DUMPABLE, 0) this link cannot be accessed. + +#ifdef __FreeBSD__ + const int mib[] = {CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, static_cast(info.pid)}; + char buffer[2048]; + size_t size = sizeof(buffer); + if (sysctl(mib, 4, buffer, &size, NULL, 0) != 0) { + strlcpy(buffer, "Invalid path", sizeof(buffer)); + } + QFileInfo exe(buffer); +#else QFileInfo exe(QStringLiteral("/proc/%1/exe").arg(pid)); +#endif info.exePath = exe.canonicalFilePath(); // /proc/pid/cmdline gives full command line diff --git a/src/fdosecrets/objects/Collection.cpp b/src/fdosecrets/objects/Collection.cpp index d16d9f552..44b0f0361 100644 --- a/src/fdosecrets/objects/Collection.cpp +++ b/src/fdosecrets/objects/Collection.cpp @@ -648,7 +648,7 @@ namespace FdoSecrets // groupPath can't be empty here, because otherwise it will match m_exposedGroup and was returned above Q_ASSERT(!groupPath.isEmpty()); - auto groups = groupPath.split('/', QString::SkipEmptyParts); + auto groups = groupPath.split('/', Qt::SkipEmptyParts); auto groupName = groups.takeLast(); // create parent group diff --git a/src/fdosecrets/objects/Item.cpp b/src/fdosecrets/objects/Item.cpp index 2c6d13435..373735205 100644 --- a/src/fdosecrets/objects/Item.cpp +++ b/src/fdosecrets/objects/Item.cpp @@ -125,7 +125,7 @@ namespace FdoSecrets // add some informative and readonly attributes attrs[ItemAttributes::UuidKey] = m_backend->uuidToHex(); attrs[ItemAttributes::PathKey] = path(); - if (m_backend->hasTotp()) { + if (m_backend->hasValidTotp()) { attrs[ItemAttributes::TotpKey] = m_backend->totp(); } return {}; diff --git a/src/fdosecrets/objects/Service.cpp b/src/fdosecrets/objects/Service.cpp index ae1e9d4b6..e3fcefeb5 100644 --- a/src/fdosecrets/objects/Service.cpp +++ b/src/fdosecrets/objects/Service.cpp @@ -543,7 +543,7 @@ namespace FdoSecrets } // switch selected to current m_databases->setCurrentWidget(dbWidget); - m_databases->showDatabaseSettings(); + m_databases->showDatabaseSettings(true); // open settings (switch from app settings to m_dbTabs) m_plugin->emitRequestSwitchToDatabases(); diff --git a/src/fdosecrets/widgets/AccessControlDialog.cpp b/src/fdosecrets/widgets/AccessControlDialog.cpp index 8e3a3e1d8..c35fd8e0c 100644 --- a/src/fdosecrets/widgets/AccessControlDialog.cpp +++ b/src/fdosecrets/widgets/AccessControlDialog.cpp @@ -24,6 +24,8 @@ #include "fdosecrets/widgets/RowButtonHelper.h" #include "core/Entry.h" +#include "core/Global.h" +#include "core/Tools.h" #include "gui/Icons.h" #include @@ -101,7 +103,7 @@ AccessControlDialog::AccessControlDialog(QWindow* parent, connect(cancelButton, &QPushButton::clicked, this, [this]() { done(DenyAll); }); connect(allowButton, &QPushButton::clicked, this, [this]() { done(AllowSelected); }); connect(allowAllButton, &QPushButton::clicked, this, [this]() { done(AllowAll); }); - connect(detailsButton, &QPushButton::clicked, this, [=](bool checked) { + connect(detailsButton, &QPushButton::clicked, this, [this, detailsButton, detailsButtonText](bool checked) { m_ui->detailsContainer->setVisible(checked); if (checked) { detailsButton->setText(detailsButtonText + QStringLiteral(" <<")); @@ -206,7 +208,7 @@ QHash AccessControlDialog::decisions() const AccessControlDialog::EntryModel::EntryModel(QList entries, QObject* parent) : QAbstractTableModel(parent) , m_entries(std::move(entries)) - , m_selected(QSet::fromList(m_entries)) + , m_selected(Tools::asSet(m_entries)) { } diff --git a/src/format/BitwardenReader.cpp b/src/format/BitwardenReader.cpp index 8f9d86b8f..5f729aa77 100644 --- a/src/format/BitwardenReader.cpp +++ b/src/format/BitwardenReader.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2023 KeePassXC Team + * Copyright (C) 2024 KeePassXC Team * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -81,6 +81,43 @@ namespace entry->setTotp(Totp::parseSettings(totp)); } + // Parse passkey + if (loginMap.contains("fido2Credentials")) { + const auto fido2CredentialsMap = loginMap.value("fido2Credentials").toList(); + for (const auto& fido2Credentials : fido2CredentialsMap) { + const auto passkey = fido2Credentials.toMap(); + + // Change from UUID to base64 byte array + const auto credentialIdValue = passkey.value("credentialId").toString(); + if (!credentialIdValue.isEmpty()) { + const auto credentialUuid = Tools::uuidToHex(credentialIdValue); + const auto credentialIdArray = QByteArray::fromHex(credentialUuid.toUtf8()); + const auto credentialId = + credentialIdArray.toBase64(QByteArray::Base64UrlEncoding | QByteArray::OmitTrailingEquals); + entry->attributes()->set(EntryAttributes::KPEX_PASSKEY_CREDENTIAL_ID, credentialId, true); + } + + // Base64 needs to be changed from URL encoding back to normal, and the result as PEM string + const auto keyValue = passkey.value("keyValue").toString(); + if (!keyValue.isEmpty()) { + const auto keyValueArray = + QByteArray::fromBase64(keyValue.toUtf8(), QByteArray::Base64UrlEncoding); + auto privateKey = keyValueArray.toBase64(QByteArray::Base64Encoding); + privateKey.insert(0, EntryAttributes::KPEX_PASSKEY_PRIVATE_KEY_START.toUtf8()); + privateKey.append(EntryAttributes::KPEX_PASSKEY_PRIVATE_KEY_END.toUtf8()); + entry->attributes()->set(EntryAttributes::KPEX_PASSKEY_PRIVATE_KEY_PEM, privateKey, true); + } + + entry->attributes()->set(EntryAttributes::KPEX_PASSKEY_USERNAME, + passkey.value("userName").toString()); + entry->attributes()->set(EntryAttributes::KPEX_PASSKEY_RELYING_PARTY, + passkey.value("rpId").toString()); + entry->attributes()->set( + EntryAttributes::KPEX_PASSKEY_USER_HANDLE, passkey.value("userHandle").toString(), true); + entry->addTag(QObject::tr("Passkey")); + } + } + // Set the entry url(s) int i = 1; for (const auto& urlObj : loginMap.value("uris").toList()) { @@ -252,14 +289,25 @@ QSharedPointer BitwardenReader::convert(const QString& path, const QSt return QObject::tr("Failed to decrypt json file: %1").arg(errorString); }; + if (!json.contains("kdfType") || !json.contains("salt")) { + m_error = buildError(QObject::tr("Unsupported format, ensure your Bitwarden export is password-protected")); + return {}; + } + QByteArray key(32, '\0'); auto salt = json.value("salt").toString().toUtf8(); auto kdfType = json.value("kdfType").toInt(); // Derive the Master Key if (kdfType == 0) { + // PBKDF2 + auto iterations = json.value("kdfIterations").toInt(); + if (iterations <= 0) { + m_error = buildError(QObject::tr("Invalid KDF iterations, cannot decrypt json file")); + return {}; + } auto pwd_fam = Botan::PasswordHashFamily::create_or_throw("PBKDF2(SHA-256)"); - auto pwd_hash = pwd_fam->from_params(json.value("kdfIterations").toInt()); + auto pwd_hash = pwd_fam->from_params(iterations); pwd_hash->derive_key(reinterpret_cast(key.data()), key.size(), password.toUtf8().data(), @@ -267,7 +315,8 @@ QSharedPointer BitwardenReader::convert(const QString& path, const QSt reinterpret_cast(salt.data()), salt.size()); } else if (kdfType == 1) { - // Bitwarden hashes the salt for Argon2 for some reason + // Argon2 + // Bitwarden hashes the salt prior to use CryptoHash saltHash(CryptoHash::Sha256); saltHash.addData(salt); salt = saltHash.result(); @@ -279,7 +328,7 @@ QSharedPointer BitwardenReader::convert(const QString& path, const QSt argon2.setParallelism(json.value("kdfParallelism").toInt()); argon2.transform(password.toUtf8(), key); } else { - m_error = buildError(QObject::tr("Unsupported KDF type, cannot decrypt json file")); + m_error = buildError(QObject::tr("Only PBKDF and Argon2 are supported, cannot decrypt json file")); return {}; } diff --git a/src/format/CsvParser.cpp b/src/format/CsvParser.cpp index 0e174fe35..d5d3b319a 100644 --- a/src/format/CsvParser.cpp +++ b/src/format/CsvParser.cpp @@ -1,4 +1,4 @@ -/* +/* * Copyright (C) 2016 Enrico Mariotti * Copyright (C) 2017 KeePassXC Team * @@ -53,7 +53,7 @@ bool CsvParser::reparse() return parseFile(); } -bool CsvParser::parse(QFile* device) +bool CsvParser::parse(QIODevice* device) { clear(); if (!device) { @@ -66,7 +66,7 @@ bool CsvParser::parse(QFile* device) return parseFile(); } -bool CsvParser::readFile(QFile* device) +bool CsvParser::readFile(QIODevice* device) { if (device->isOpen()) { device->close(); @@ -79,6 +79,7 @@ bool CsvParser::readFile(QFile* device) } else { device->close(); + // Normalize on newline endings m_array.replace("\r\n", "\n"); m_array.replace("\r", "\n"); if (m_array.isEmpty()) { @@ -121,7 +122,7 @@ bool CsvParser::parseFile() parseRecord(); while (!m_isEof) { if (!skipEndline()) { - appendStatusMsg(QObject::tr("malformed string"), true); + appendStatusMsg(QObject::tr("malformed string, possible unescaped delimiter"), true); } m_currRow++; m_currCol = 1; @@ -161,7 +162,7 @@ void CsvParser::parseField(CsvRow& row) { QString field; peek(m_ch); - if (m_ch != m_separator && m_ch != '\n' && m_ch != '\r') { + if (m_ch != m_separator && m_ch != '\n') { if (isQualifier(m_ch)) { parseQuoted(field); } else { @@ -190,7 +191,7 @@ void CsvParser::parseQuoted(QString& s) getChar(m_ch); parseEscaped(s); if (!isQualifier(m_ch)) { - appendStatusMsg(QObject::tr("missing closing quote"), true); + appendStatusMsg(QObject::tr("missing closing delimiter"), true); } } @@ -391,6 +392,12 @@ int CsvParser::getCsvRows() const void CsvParser::appendStatusMsg(const QString& s, bool isCritical) { - m_statusMsg += QObject::tr("%1: (row, col) %2,%3").arg(s, m_currRow, m_currCol).append("\n"); + if (!m_statusMsg.isEmpty()) { + m_statusMsg.append("\n"); + } + + m_statusMsg += + QObject::tr("%1, row: %2, column: %3").arg(s, QString::number(m_currRow), QString::number(m_currCol)); + m_isGood = !isCritical; } diff --git a/src/format/CsvParser.h b/src/format/CsvParser.h index afba9688d..608d71c14 100644 --- a/src/format/CsvParser.h +++ b/src/format/CsvParser.h @@ -22,7 +22,7 @@ #include #include -class QFile; +class QIODevice; typedef QStringList CsvRow; typedef QList CsvTable; @@ -34,7 +34,7 @@ public: CsvParser(); ~CsvParser(); // read data from device and parse it - bool parse(QFile* device); + bool parse(QIODevice* device); bool isFileLoaded(); // reparse the same buffer (device is not opened again) bool reparse(); @@ -85,7 +85,7 @@ private: void parseQuoted(QString& s); void parseEscaped(QString& s); void parseEscapedText(QString& s); - bool readFile(QFile* device); + bool readFile(QIODevice* device); void reset(); void clear(); bool skipEndline(); diff --git a/src/gui/HtmlExporter.cpp b/src/format/HtmlExporter.cpp similarity index 81% rename from src/gui/HtmlExporter.cpp rename to src/format/HtmlExporter.cpp index 654909463..933df4e35 100644 --- a/src/gui/HtmlExporter.cpp +++ b/src/format/HtmlExporter.cpp @@ -17,28 +17,13 @@ #include "HtmlExporter.h" -#include #include #include "core/Group.h" #include "core/Metadata.h" -#include "gui/Icons.h" namespace { - QString PixmapToHTML(const QPixmap& pixmap) - { - if (pixmap.isNull()) { - return ""; - } - - // Based on https://stackoverflow.com/a/6621278 - QByteArray a; - QBuffer buffer(&a); - pixmap.save(&buffer, "PNG"); - return QString(""; - } - QString formatEntry(const Entry& entry) { // Here we collect the table rows with this entry's data fields @@ -127,15 +112,62 @@ QString HtmlExporter::errorString() const return m_error; } +QString HtmlExporter::groupIconToHtml(const Group* /* group */) +{ + return ""; +} + +QString HtmlExporter::entryIconToHtml(const Entry* /* entry */) +{ + return ""; +} + bool HtmlExporter::exportDatabase(QIODevice* device, const QSharedPointer& db, bool sorted, bool ascending) +{ + if (device->write(exportHeader(db).toUtf8()) == -1) { + m_error = device->errorString(); + return false; + } + + if (db->rootGroup()) { + if (device->write(exportGroup(*db->rootGroup(), QString(), sorted, ascending).toUtf8()) == -1) { + m_error = device->errorString(); + return false; + } + } + + if (device->write(exportFooter().toUtf8()) == -1) { + m_error = device->errorString(); + return false; + } + + return true; +} + +QString HtmlExporter::exportDatabase(const QSharedPointer& db, bool sorted, bool ascending) +{ + QString response; + + response = exportHeader(db); + if (!response.isEmpty()) { + if (db->rootGroup()) { + response.append(exportGroup(*db->rootGroup(), QString(), sorted, ascending)); + } + response.append(exportFooter()); + } + + return response; +} + +QString HtmlExporter::exportHeader(const QSharedPointer& db) { const auto meta = db->metadata(); if (!meta) { m_error = "Internal error: metadata is NULL"; - return false; + return ""; } const auto header = QString("" @@ -149,8 +181,6 @@ bool HtmlExporter::exportDatabase(QIODevice* device, "{ font-family: \"Open Sans\", Helvetica, Arial, sans-serif; }" "h3 " "{ margin-left: 2em; }" - "table " - "{ margin-left: 1em; } " "caption " "{ text-align: left; font-weight: bold; font-size: 150%; border-bottom: .15em solid " "#4ca; margin-bottom: .5em;} " @@ -159,7 +189,7 @@ bool HtmlExporter::exportDatabase(QIODevice* device, "th " "{ min-width: 7em; width: 15%; } " ".username, .password, .url, .attr " - "{ font-size: larger; font-family: monospace; } " + "{ font-size: larger; font-family: monospace; overflow-wrap: anywhere;} " ".notes " "{ font-size: small; } " "" @@ -173,33 +203,23 @@ bool HtmlExporter::exportDatabase(QIODevice* device, + "

    " "

    " + db->filePath().toHtmlEscaped() + "

    "); - const auto footer = QString("" - ""); - - if (device->write(header.toUtf8()) == -1) { - m_error = device->errorString(); - return false; - } - - if (db->rootGroup()) { - if (!writeGroup(*device, *db->rootGroup(), QString(), sorted, ascending)) { - return false; - } - } - - if (device->write(footer.toUtf8()) == -1) { - m_error = device->errorString(); - return false; - } - - return true; + return header; } -bool HtmlExporter::writeGroup(QIODevice& device, const Group& group, QString path, bool sorted, bool ascending) +QString HtmlExporter::exportFooter() { + const auto footer = QString("" + ""); + return footer; +} + +QString HtmlExporter::exportGroup(const Group& group, QString path, bool sorted, bool ascending) +{ + QString response = ""; + // Don't output the recycle bin if (&group == group.database()->metadata()->recycleBin()) { - return true; + return response; } if (!path.isEmpty()) { @@ -214,8 +234,11 @@ bool HtmlExporter::writeGroup(QIODevice& device, const Group& group, QString pat if (!group.entries().empty() || !notes.isEmpty()) { // Header line auto header = QString("

    "); - header.append(PixmapToHTML(Icons::groupIconPixmap(&group, IconSize::Medium))); - header.append(" "); + auto groupIcon = this->groupIconToHtml(&group); + if (!groupIcon.isEmpty()) { + header.append(groupIcon); + header.append(" "); + } header.append(path); header.append("

    \n"); @@ -226,11 +249,8 @@ bool HtmlExporter::writeGroup(QIODevice& device, const Group& group, QString pat header.append("

    "); } - // Output it - if (device.write(header.toUtf8()) == -1) { - m_error = device.errorString(); - return false; - } + // Append it to the output + response.append(header); } // Begin the table for the entries in this group @@ -244,7 +264,7 @@ bool HtmlExporter::writeGroup(QIODevice& device, const Group& group, QString pat }); } - // Output the entries in this group + // Append to the output the entries in this group for (const auto* entry : entries) { auto formatted_entry = formatEntry(*entry); @@ -254,7 +274,10 @@ bool HtmlExporter::writeGroup(QIODevice& device, const Group& group, QString pat // Output it into our table. First the left side with // icon and entry title ... table += ""; - table += "" + PixmapToHTML(Icons::entryIconPixmap(entry, IconSize::Medium)) + ""; + auto entryIcon = this->entryIconToHtml(entry); + if (!entryIcon.isEmpty()) { + table += "" + entryIcon + ""; + } auto caption = "" + entry->title().toHtmlEscaped() + ""; // ... then the right side with the data fields @@ -263,12 +286,9 @@ bool HtmlExporter::writeGroup(QIODevice& device, const Group& group, QString pat table += ""; } - // Output the complete table of this group + // Append the complete table of this group to the output table.append("\n"); - if (device.write(table.toUtf8()) == -1) { - m_error = device.errorString(); - return false; - } + response.append(table); auto children = group.children(); if (sorted) { @@ -278,12 +298,12 @@ bool HtmlExporter::writeGroup(QIODevice& device, const Group& group, QString pat }); } - // Recursively output the child groups + // Recursively append to the output the child groups for (const auto* child : children) { - if (child && !writeGroup(device, *child, path, sorted, ascending)) { - return false; + if (child) { + response.append(exportGroup(*child, path, sorted, ascending)); } } - return true; + return response; } diff --git a/src/gui/HtmlExporter.h b/src/format/HtmlExporter.h similarity index 73% rename from src/gui/HtmlExporter.h rename to src/format/HtmlExporter.h index 1ee9b4448..0fd2612c7 100644 --- a/src/gui/HtmlExporter.h +++ b/src/format/HtmlExporter.h @@ -21,6 +21,8 @@ #include #include +#include "core/Group.h" + class Database; class Group; class QIODevice; @@ -32,18 +34,23 @@ public: const QSharedPointer& db, bool sorted = true, bool ascending = true); - QString errorString() const; - -private: bool exportDatabase(QIODevice* device, const QSharedPointer& db, bool sorted = true, bool ascending = true); - bool writeGroup(QIODevice& device, - const Group& group, - QString path = QString(), - bool sorted = true, - bool ascending = true); + QString exportDatabase(const QSharedPointer& db, bool sorted = true, bool ascending = true); + QString errorString() const; + + virtual ~HtmlExporter() = default; + +protected: + virtual QString groupIconToHtml(const Group* group); + virtual QString entryIconToHtml(const Entry* entry); + +private: + QString exportGroup(const Group& group, QString path = QString(), bool sorted = true, bool ascending = true); + QString exportHeader(const QSharedPointer& db); + QString exportFooter(); QString m_error; }; diff --git a/src/format/Kdbx4Writer.cpp b/src/format/Kdbx4Writer.cpp index d8f412b05..1c728ac81 100644 --- a/src/format/Kdbx4Writer.cpp +++ b/src/format/Kdbx4Writer.cpp @@ -23,10 +23,6 @@ #include "crypto/CryptoHash.h" #include "crypto/Random.h" #include "format/KeePass2RandomStream.h" -#ifdef WITH_XC_KEESHARE -#include "keeshare/KeeShare.h" -#include "keeshare/KeeShareSettings.h" -#endif #include "streams/HmacBlockStream.h" #include "streams/SymmetricCipherStream.h" #include "streams/qtiocompressor.h" @@ -232,8 +228,12 @@ KdbxXmlWriter::BinaryIdxMap Kdbx4Writer::writeAttachments(QIODevice* device, Dat #ifdef WITH_XC_KEESHARE // Namespace KeeShare attachments so they don't get deduplicated together with attachments // from other databases. Prevents potential filesize side channels. - if (auto shared = KeeShare::resolveSharedGroup(entry->group())) { - hash.addData(KeeShare::referenceOf(shared).uuid.toByteArray()); + auto group = entry->group(); + if (!group && entry->historyOwner()) { + group = entry->historyOwner()->group(); + } + if (group && group->isShared()) { + hash.addData(group->uuid().toByteArray()); } else { hash.addData(db->uuid().toByteArray()); } diff --git a/src/format/KdbxReader.cpp b/src/format/KdbxReader.cpp index 5610897c8..b552bd1cb 100644 --- a/src/format/KdbxReader.cpp +++ b/src/format/KdbxReader.cpp @@ -27,6 +27,8 @@ /** * Read KDBX magic header numbers from a device. * + * Passing a null key will only read in the unprotected headers. + * * @param device input device * @param sig1 KDBX signature 1 * @param sig2 KDBX signature 2 @@ -55,6 +57,8 @@ bool KdbxReader::readMagicNumbers(QIODevice* device, quint32& sig1, quint32& sig * Read KDBX stream from device. * The device will automatically be reset to 0 before reading. * + * Passing a null key will only read in the unprotected headers. + * * @param device input device * @param key database encryption composite key * @param db database to read into @@ -91,6 +95,11 @@ bool KdbxReader::readDatabase(QIODevice* device, QSharedPointerformatVersion()); + KdbxXmlWriter::BinaryIdxMap idxMap; + KdbxXmlWriter writer(db->formatVersion(), idxMap); writer.disableInnerStreamProtection(true); writer.writeDatabase(&buffer, db); } diff --git a/src/format/KdbxXmlReader.cpp b/src/format/KdbxXmlReader.cpp index a610cddb1..e6c212bbc 100644 --- a/src/format/KdbxXmlReader.cpp +++ b/src/format/KdbxXmlReader.cpp @@ -19,6 +19,7 @@ #include "KeePass2RandomStream.h" #include "core/Clock.h" #include "core/Endian.h" +#include "core/Global.h" #include "core/Group.h" #include "core/Tools.h" #include "streams/qtiocompressor.h" @@ -120,8 +121,8 @@ void KdbxXmlReader::readDatabase(QIODevice* device, Database* db, KeePass2Random qWarning("KdbxXmlReader::readDatabase: found %d invalid entry reference(s)", m_tmpParent->children().size()); } - const QSet poolKeys = asConst(m_binaryPool).keys().toSet(); - const QSet entryKeys = asConst(m_binaryMap).keys().toSet(); + const QSet poolKeys = Tools::asSet(m_binaryPool.keys()); + const QSet entryKeys = Tools::asSet(m_binaryMap.keys()); const QSet unmappedKeys = entryKeys - poolKeys; const QSet unusedKeys = poolKeys - entryKeys; @@ -133,7 +134,7 @@ void KdbxXmlReader::readDatabase(QIODevice* device, Database* db, KeePass2Random qWarning("KdbxXmlReader::readDatabase: found unused key \"%s\"", qPrintable(key)); } - QHash>::const_iterator i; + QMultiHash>::const_iterator i; for (i = m_binaryMap.constBegin(); i != m_binaryMap.constEnd(); ++i) { const QPair& target = i.value(); target.first->attachments()->set(target.second, m_binaryPool[i.key()]); @@ -183,7 +184,7 @@ QString KdbxXmlReader::errorString() const .arg(m_xml.lineNumber()) .arg(m_xml.columnNumber()); } - return QString(); + return {}; } bool KdbxXmlReader::isTrueValue(const QStringRef& value) @@ -814,7 +815,7 @@ Entry* KdbxXmlReader::parseEntry(bool history) } for (const StringPair& ref : asConst(binaryRefs)) { - m_binaryMap.insertMulti(ref.first, qMakePair(entry, ref.second)); + m_binaryMap.insert(ref.first, qMakePair(entry, ref.second)); } return entry; @@ -1116,13 +1117,13 @@ QUuid KdbxXmlReader::readUuid() { QByteArray uuidBin = readBinary(); if (uuidBin.isEmpty()) { - return QUuid(); + return {}; } if (uuidBin.length() != UUID_LENGTH) { if (m_strictMode) { raiseError(tr("Invalid uuid value")); } - return QUuid(); + return {}; } return QUuid::fromRfc4122(uuidBin); } diff --git a/src/format/KdbxXmlReader.h b/src/format/KdbxXmlReader.h index 44978b083..1b6305eea 100644 --- a/src/format/KdbxXmlReader.h +++ b/src/format/KdbxXmlReader.h @@ -22,6 +22,7 @@ #include "core/Metadata.h" #include +#include #include class QIODevice; @@ -109,7 +110,7 @@ protected: QHash m_entries; QHash m_binaryPool; - QHash> m_binaryMap; + QMultiHash> m_binaryMap; QByteArray m_headerHash; bool m_error = false; diff --git a/src/format/KdbxXmlWriter.cpp b/src/format/KdbxXmlWriter.cpp index 53a7bfae9..142f4b7e3 100644 --- a/src/format/KdbxXmlWriter.cpp +++ b/src/format/KdbxXmlWriter.cpp @@ -24,8 +24,6 @@ #include "core/Endian.h" #include "crypto/CryptoHash.h" #include "format/KeePass2RandomStream.h" -#include "keeshare/KeeShare.h" -#include "keeshare/KeeShareSettings.h" #include "streams/qtiocompressor.h" /** @@ -114,8 +112,12 @@ void KdbxXmlWriter::fillBinaryIdxMap() #ifdef WITH_XC_KEESHARE // Namespace KeeShare attachments so they don't get deduplicated together with attachments // from other databases. Prevents potential filesize side channels. - if (auto shared = KeeShare::resolveSharedGroup(entry->group())) { - hash.addData(KeeShare::referenceOf(shared).uuid.toByteArray()); + auto group = entry->group(); + if (!group && entry->historyOwner()) { + group = entry->historyOwner()->group(); + } + if (group && group->isShared()) { + hash.addData(group->uuid().toByteArray()); } else { hash.addData(m_db->uuid().toByteArray()); } diff --git a/src/format/KeePass1Reader.cpp b/src/format/KeePass1Reader.cpp index 1461b22c5..a7d8038df 100644 --- a/src/format/KeePass1Reader.cpp +++ b/src/format/KeePass1Reader.cpp @@ -396,7 +396,7 @@ QByteArray KeePass1Reader::key(const QByteArray& password, const QByteArray& key if (!result) { raiseError(tr("Key transformation failed")); - return QByteArray(); + return {}; } CryptoHash hash(CryptoHash::Sha256); @@ -437,13 +437,13 @@ Group* KeePass1Reader::readGroup(QIODevice* cipherStream) bool reachedEnd = false; do { - quint16 fieldType = Endian::readSizedInt(cipherStream, KeePass1::BYTEORDER, &ok); + auto fieldType = Endian::readSizedInt(cipherStream, KeePass1::BYTEORDER, &ok); if (!ok) { raiseError(tr("Invalid group field type number")); return nullptr; } - int fieldSize = static_cast(Endian::readSizedInt(cipherStream, KeePass1::BYTEORDER, &ok)); + auto fieldSize = static_cast(Endian::readSizedInt(cipherStream, KeePass1::BYTEORDER, &ok)); if (!ok) { raiseError(tr("Invalid group field size")); return nullptr; @@ -518,7 +518,7 @@ Group* KeePass1Reader::readGroup(QIODevice* cipherStream) raiseError(tr("Incorrect group icon field size")); return nullptr; } - quint32 iconNumber = Endian::bytesToSizedInt(fieldData, KeePass1::BYTEORDER); + auto iconNumber = Endian::bytesToSizedInt(fieldData, KeePass1::BYTEORDER); group->setIcon(iconNumber); break; } @@ -569,13 +569,13 @@ Entry* KeePass1Reader::readEntry(QIODevice* cipherStream) bool reachedEnd = false; do { - quint16 fieldType = Endian::readSizedInt(cipherStream, KeePass1::BYTEORDER, &ok); + auto fieldType = Endian::readSizedInt(cipherStream, KeePass1::BYTEORDER, &ok); if (!ok) { raiseError(tr("Missing entry field type number")); return nullptr; } - int fieldSize = static_cast(Endian::readSizedInt(cipherStream, KeePass1::BYTEORDER, &ok)); + auto fieldSize = static_cast(Endian::readSizedInt(cipherStream, KeePass1::BYTEORDER, &ok)); if (!ok) { raiseError(tr("Invalid entry field size")); return nullptr; @@ -603,7 +603,7 @@ Entry* KeePass1Reader::readEntry(QIODevice* cipherStream) raiseError(tr("Invalid entry group id field size")); return nullptr; } - quint32 groupId = Endian::bytesToSizedInt(fieldData, KeePass1::BYTEORDER); + auto groupId = Endian::bytesToSizedInt(fieldData, KeePass1::BYTEORDER); m_entryGroupIds.insert(entry.data(), groupId); break; } @@ -612,7 +612,7 @@ Entry* KeePass1Reader::readEntry(QIODevice* cipherStream) raiseError(tr("Invalid entry icon field size")); return nullptr; } - quint32 iconNumber = Endian::bytesToSizedInt(fieldData, KeePass1::BYTEORDER); + auto iconNumber = Endian::bytesToSizedInt(fieldData, KeePass1::BYTEORDER); entry->setIcon(iconNumber); break; } @@ -811,7 +811,7 @@ bool KeePass1Reader::parseGroupTreeState(const QByteArray& data) } int pos = 0; - quint32 num = Endian::bytesToSizedInt(data.mid(pos, 4), KeePass1::BYTEORDER); + auto num = Endian::bytesToSizedInt(data.mid(pos, 4), KeePass1::BYTEORDER); pos += 4; if (static_cast(data.size() - 4) != (num * 5)) { @@ -819,7 +819,7 @@ bool KeePass1Reader::parseGroupTreeState(const QByteArray& data) } for (quint32 i = 0; i < num; i++) { - quint32 groupId = Endian::bytesToSizedInt(data.mid(pos, 4), KeePass1::BYTEORDER); + auto groupId = Endian::bytesToSizedInt(data.mid(pos, 4), KeePass1::BYTEORDER); pos += 4; bool expanded = data.at(pos); @@ -841,13 +841,13 @@ bool KeePass1Reader::parseCustomIcons4(const QByteArray& data) int pos = 0; - quint32 numIcons = Endian::bytesToSizedInt(data.mid(pos, 4), KeePass1::BYTEORDER); + auto numIcons = Endian::bytesToSizedInt(data.mid(pos, 4), KeePass1::BYTEORDER); pos += 4; - quint32 numEntries = Endian::bytesToSizedInt(data.mid(pos, 4), KeePass1::BYTEORDER); + auto numEntries = Endian::bytesToSizedInt(data.mid(pos, 4), KeePass1::BYTEORDER); pos += 4; - quint32 numGroups = Endian::bytesToSizedInt(data.mid(pos, 4), KeePass1::BYTEORDER); + auto numGroups = Endian::bytesToSizedInt(data.mid(pos, 4), KeePass1::BYTEORDER); pos += 4; QList iconUuids; @@ -856,7 +856,7 @@ bool KeePass1Reader::parseCustomIcons4(const QByteArray& data) if (data.size() < (pos + 4)) { return false; } - quint32 iconSize = Endian::bytesToSizedInt(data.mid(pos, 4), KeePass1::BYTEORDER); + auto iconSize = Endian::bytesToSizedInt(data.mid(pos, 4), KeePass1::BYTEORDER); pos += 4; if (static_cast(data.size()) < (pos + iconSize)) { @@ -878,7 +878,7 @@ bool KeePass1Reader::parseCustomIcons4(const QByteArray& data) QByteArray entryUuid = data.mid(pos, 16); pos += 16; - quint32 iconId = Endian::bytesToSizedInt(data.mid(pos, 4), KeePass1::BYTEORDER); + auto iconId = Endian::bytesToSizedInt(data.mid(pos, 4), KeePass1::BYTEORDER); pos += 4; if (m_entryUuids.contains(entryUuid) && (iconId < static_cast(iconUuids.size()))) { @@ -891,10 +891,10 @@ bool KeePass1Reader::parseCustomIcons4(const QByteArray& data) } for (quint32 i = 0; i < numGroups; i++) { - quint32 groupId = Endian::bytesToSizedInt(data.mid(pos, 4), KeePass1::BYTEORDER); + auto groupId = Endian::bytesToSizedInt(data.mid(pos, 4), KeePass1::BYTEORDER); pos += 4; - quint32 iconId = Endian::bytesToSizedInt(data.mid(pos, 4), KeePass1::BYTEORDER); + auto iconId = Endian::bytesToSizedInt(data.mid(pos, 4), KeePass1::BYTEORDER); pos += 4; if (m_groupIds.contains(groupId) && (iconId < static_cast(iconUuids.size()))) { @@ -932,7 +932,7 @@ QDateTime KeePass1Reader::dateFromPackedStruct(const QByteArray& data) // check for the special "never" datetime if (dateTime == QDateTime(QDate(2999, 12, 28), QTime(23, 59, 59), Qt::UTC)) { - return QDateTime(); + return {}; } else { return dateTime; } @@ -948,13 +948,13 @@ bool KeePass1Reader::isMetaStream(const Entry* entry) QByteArray KeePass1Reader::readKeyfile(QIODevice* device) { if (device->size() == 0) { - return QByteArray(); + return {}; } if (device->size() == 32) { QByteArray data = device->read(32); if (data.size() != 32) { - return QByteArray(); + return {}; } return data; @@ -964,7 +964,7 @@ QByteArray KeePass1Reader::readKeyfile(QIODevice* device) QByteArray data = device->read(64); if (data.size() != 64) { - return QByteArray(); + return {}; } if (Tools::isHex(data)) { @@ -979,7 +979,7 @@ QByteArray KeePass1Reader::readKeyfile(QIODevice* device) do { if (!Tools::readFromDevice(device, buffer)) { - return QByteArray(); + return {}; } cryptoHash.addData(buffer); } while (!buffer.isEmpty()); diff --git a/src/format/KeePass2.cpp b/src/format/KeePass2.cpp index b19316741..c068384ad 100644 --- a/src/format/KeePass2.cpp +++ b/src/format/KeePass2.cpp @@ -49,10 +49,8 @@ const QString KeePass2::KDFPARAM_ARGON2_ASSOCDATA("A"); const QList KeePass2::CIPHERS{KeePass2::CIPHER_AES256, KeePass2::CIPHER_TWOFISH, KeePass2::CIPHER_CHACHA20}; -const QList KeePass2::KDFS{KeePass2::KDF_ARGON2D, - KeePass2::KDF_ARGON2ID, - KeePass2::KDF_AES_KDBX4, - KeePass2::KDF_AES_KDBX3}; +const QList KeePass2::KDBX4_KDFS{KeePass2::KDF_ARGON2D, KeePass2::KDF_ARGON2ID, KeePass2::KDF_AES_KDBX4}; +const QList KeePass2::KDBX3_KDFS{KeePass2::KDF_AES_KDBX3}; QByteArray KeePass2::hmacKey(const QByteArray& masterSeed, const QByteArray& transformedMasterKey) { diff --git a/src/format/KeePass2.h b/src/format/KeePass2.h index 1d18a18ba..82b6e1674 100644 --- a/src/format/KeePass2.h +++ b/src/format/KeePass2.h @@ -67,7 +67,8 @@ namespace KeePass2 extern const QString KDFPARAM_ARGON2_ASSOCDATA; extern const QList CIPHERS; - extern const QList KDFS; + extern const QList KDBX4_KDFS; + extern const QList KDBX3_KDFS; enum class HeaderFieldID { diff --git a/src/format/KeePass2RandomStream.cpp b/src/format/KeePass2RandomStream.cpp index 509e32513..da6df20ad 100644 --- a/src/format/KeePass2RandomStream.cpp +++ b/src/format/KeePass2RandomStream.cpp @@ -50,7 +50,7 @@ QByteArray KeePass2RandomStream::randomBytes(int size, bool* ok) if (m_buffer.size() == m_offset) { if (!loadBlock()) { *ok = false; - return QByteArray(); + return {}; } } @@ -71,7 +71,7 @@ QByteArray KeePass2RandomStream::process(const QByteArray& data, bool* ok) QByteArray randomData = randomBytes(data.size(), &randomBytesOk); if (!randomBytesOk) { *ok = false; - return QByteArray(); + return {}; } QByteArray result; diff --git a/src/format/KeePass2Writer.cpp b/src/format/KeePass2Writer.cpp index 4cf0d4ad6..76e8cacc3 100644 --- a/src/format/KeePass2Writer.cpp +++ b/src/format/KeePass2Writer.cpp @@ -184,7 +184,7 @@ void KeePass2Writer::raiseError(const QString& errorMessage) */ QSharedPointer KeePass2Writer::writer() const { - return QSharedPointer(); + return {}; } /** diff --git a/src/format/OPUXReader.cpp b/src/format/OPUXReader.cpp index ee5869b69..e1a0579cf 100644 --- a/src/format/OPUXReader.cpp +++ b/src/format/OPUXReader.cpp @@ -102,6 +102,9 @@ namespace entry->setPassword(fieldMap.value("value").toString()); } } + if (entry->password().isEmpty() && detailsMap.contains("password")) { + entry->setPassword(detailsMap.value("password").toString()); + } entry->setNotes(detailsMap.value("notesPlain").toString()); // Dive into the item sections to pull out advanced attributes diff --git a/src/format/OpData01.cpp b/src/format/OpData01.cpp index 3ded0288c..a51ff8fdb 100644 --- a/src/format/OpData01.cpp +++ b/src/format/OpData01.cpp @@ -27,9 +27,7 @@ OpData01::OpData01(QObject* parent) { } -OpData01::~OpData01() -{ -} +OpData01::~OpData01() = default; bool OpData01::decodeBase64(QString const& b64String, const QByteArray& key, const QByteArray& hmacKey) { diff --git a/src/format/OpData01.h b/src/format/OpData01.h index df6a0b442..960c67b1f 100644 --- a/src/format/OpData01.h +++ b/src/format/OpData01.h @@ -22,7 +22,7 @@ /*! * Packages and transports the AgileBits data structure called \c OpData01 - * used to encypt and provide HMAC for encrypted data. + * used to encrypt and provide HMAC for encrypted data. * \sa https://support.1password.com/opvault-design/#opdata01 */ class OpData01 : public QObject diff --git a/src/format/OpVaultReader.cpp b/src/format/OpVaultReader.cpp index fa4034a00..779e25fda 100644 --- a/src/format/OpVaultReader.cpp +++ b/src/format/OpVaultReader.cpp @@ -34,9 +34,7 @@ OpVaultReader::OpVaultReader(QObject* parent) { } -OpVaultReader::~OpVaultReader() -{ -} +OpVaultReader::~OpVaultReader() = default; QSharedPointer OpVaultReader::convert(QDir& opdataDir, const QString& password) { @@ -273,11 +271,11 @@ QJsonObject OpVaultReader::readAndAssertJsonFile(QFile& file, const QString& str auto absFilePath = fileInfo.absoluteFilePath(); if (!fileInfo.exists()) { qCritical() << QString("File \"%1\" must exist").arg(absFilePath); - return QJsonObject(); + return {}; } if (!fileInfo.isReadable()) { qCritical() << QString("File \"%1\" must be readable").arg(absFilePath); - return QJsonObject(); + return {}; } if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { @@ -303,7 +301,7 @@ QJsonObject OpVaultReader::readAndAssertJsonFile(QFile& file, const QString& str QJsonDocument jDoc = QJsonDocument::fromJson(filePayload, error); if (!jDoc.isObject()) { qCritical() << "Expected " << filePayload << "to be a JSON Object"; - return QJsonObject(); + return {}; } return jDoc.object(); } diff --git a/src/format/OpVaultReaderSections.cpp b/src/format/OpVaultReaderSections.cpp index 42da14bb6..02566a542 100644 --- a/src/format/OpVaultReaderSections.cpp +++ b/src/format/OpVaultReaderSections.cpp @@ -23,6 +23,7 @@ #include #include #include +#include #include namespace @@ -120,7 +121,7 @@ void OpVaultReader::fillFromSectionField(Entry* entry, const QString& sectionNam if (kind == "date" || kind == "monthYear") { QDateTime date = resolveDate(kind, field.value("v")); if (date.isValid()) { - entry->attributes()->set(attrName, date.toString(Qt::SystemLocaleShortDate)); + entry->attributes()->set(attrName, QLocale::system().toString(date, QLocale::ShortFormat)); } else { qWarning() << QString("[%1] Invalid date attribute found: %2 = %3").arg(entry->title(), attrName, attrValue); diff --git a/src/format/ProtonPassReader.cpp b/src/format/ProtonPassReader.cpp new file mode 100644 index 000000000..b835406ee --- /dev/null +++ b/src/format/ProtonPassReader.cpp @@ -0,0 +1,227 @@ +/* + * Copyright (C) 2024 KeePassXC Team + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 or (at your option) + * version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "ProtonPassReader.h" + +#include "core/Database.h" +#include "core/Entry.h" +#include "core/Group.h" +#include "core/Metadata.h" +#include "core/Tools.h" +#include "core/Totp.h" +#include "crypto/CryptoHash.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace +{ + Entry* readItem(const QJsonObject& item) + { + const auto itemMap = item.toVariantMap(); + const auto dataMap = itemMap.value("data").toMap(); + const auto metadataMap = dataMap.value("metadata").toMap(); + + // Create entry and assign basic values + QScopedPointer entry(new Entry()); + entry->setUuid(QUuid::createUuid()); + entry->setTitle(metadataMap.value("name").toString()); + entry->setNotes(metadataMap.value("note").toString()); + + if (itemMap.value("pinned").toBool()) { + entry->addTag(QObject::tr("Favorite", "Tag for favorite entries")); + } + + // Handle specific item types + auto type = dataMap.value("type").toString(); + + // Login + if (type.compare("login", Qt::CaseInsensitive) == 0) { + const auto loginMap = dataMap.value("content").toMap(); + entry->setUsername(loginMap.value("itemUsername").toString()); + entry->setPassword(loginMap.value("password").toString()); + if (loginMap.contains("totpUri")) { + auto totp = loginMap.value("totpUri").toString(); + if (!totp.startsWith("otpauth://")) { + QUrl url(QString("otpauth://totp/%1:%2?secret=%3") + .arg(QString(QUrl::toPercentEncoding(entry->title())), + QString(QUrl::toPercentEncoding(entry->username())), + QString(QUrl::toPercentEncoding(totp)))); + totp = url.toString(QUrl::FullyEncoded); + } + entry->setTotp(Totp::parseSettings(totp)); + } + + if (loginMap.contains("itemEmail")) { + // Place the email value as the username if empty, otherwise set it as an attribute + const auto email = loginMap.value("itemEmail").toString(); + if (entry->username().isEmpty()) { + entry->setUsername(email); + } else if (!email.isEmpty()) { + entry->attributes()->set("login_email", email); + } + } + + // Set the entry url(s) + int i = 1; + for (const auto& urlObj : loginMap.value("urls").toList()) { + const auto url = urlObj.toString(); + if (entry->url().isEmpty()) { + // First url encountered is set as the primary url + entry->setUrl(url); + } else { + // Subsequent urls + entry->attributes()->set( + QString("%1_%2").arg(EntryAttributes::AdditionalUrlAttribute, QString::number(i)), url); + ++i; + } + } + } + // Credit Card + else if (type.compare("creditCard", Qt::CaseInsensitive) == 0) { + const auto cardMap = dataMap.value("content").toMap(); + entry->setUsername(cardMap.value("number").toString()); + entry->setPassword(cardMap.value("verificationNumber").toString()); + const QStringList attrs({"cardholderName", "pin", "expirationDate"}); + const QStringList sensitive({"pin"}); + for (const auto& attr : attrs) { + auto value = cardMap.value(attr).toString(); + if (!value.isEmpty()) { + entry->attributes()->set("card_" + attr, value, sensitive.contains(attr)); + } + } + } + + // Parse extra fields + for (const auto& field : dataMap.value("extraFields").toList()) { + // Derive a prefix for attribute names using the title or uuid if missing + const auto fieldMap = field.toMap(); + auto name = fieldMap.value("fieldName").toString(); + if (entry->attributes()->hasKey(name)) { + name = QString("%1_%2").arg(name, QUuid::createUuid().toString().mid(1, 5)); + } + + QString value; + const auto fieldType = fieldMap.value("type").toString(); + if (fieldType.compare("totp", Qt::CaseInsensitive) == 0) { + value = fieldMap.value("data").toJsonObject().value("totpUri").toString(); + } else { + value = fieldMap.value("data").toJsonObject().value("content").toString(); + } + + entry->attributes()->set(name, value, fieldType.compare("hidden", Qt::CaseInsensitive) == 0); + } + + // Checked expired/deleted state + if (itemMap.value("state").toInt() == 2) { + entry->setExpires(true); + entry->setExpiryTime(QDateTime::currentDateTimeUtc()); + } + + // Collapse any accumulated history + entry->removeHistoryItems(entry->historyItems()); + + // Adjust the created and modified times + auto timeInfo = entry->timeInfo(); + const auto createdTime = QDateTime::fromSecsSinceEpoch(itemMap.value("createTime").toULongLong(), Qt::UTC); + const auto modifiedTime = QDateTime::fromSecsSinceEpoch(itemMap.value("modifyTime").toULongLong(), Qt::UTC); + timeInfo.setCreationTime(createdTime); + timeInfo.setLastModificationTime(modifiedTime); + timeInfo.setLastAccessTime(modifiedTime); + entry->setTimeInfo(timeInfo); + + return entry.take(); + } + + void writeVaultToDatabase(const QJsonObject& vault, QSharedPointer db) + { + // Create groups from vaults and store a temporary map of id -> uuid + const auto vaults = vault.value("vaults").toObject().toVariantMap(); + for (const auto& vaultId : vaults.keys()) { + auto vaultObj = vaults.value(vaultId).toJsonObject(); + auto group = new Group(); + group->setUuid(QUuid::createUuid()); + group->setName(vaultObj.value("name").toString()); + group->setNotes(vaultObj.value("description").toString()); + group->setParent(db->rootGroup()); + + const auto items = vaultObj.value("items").toArray(); + for (const auto& item : items) { + auto entry = readItem(item.toObject()); + if (entry) { + entry->setGroup(group, false); + } + } + } + } +} // namespace + +bool ProtonPassReader::hasError() +{ + return !m_error.isEmpty(); +} + +QString ProtonPassReader::errorString() +{ + return m_error; +} + +QSharedPointer ProtonPassReader::convert(const QString& path) +{ + m_error.clear(); + + QFileInfo fileinfo(path); + if (!fileinfo.exists()) { + m_error = QObject::tr("File does not exist.").arg(path); + return {}; + } + + // Bitwarden uses a json file format + QFile file(fileinfo.absoluteFilePath()); + if (!file.open(QFile::ReadOnly)) { + m_error = QObject::tr("Cannot open file: %1").arg(file.errorString()); + return {}; + } + + QJsonParseError error; + auto json = QJsonDocument::fromJson(file.readAll(), &error).object(); + if (error.error != QJsonParseError::NoError) { + m_error = + QObject::tr("Cannot parse file: %1 at position %2").arg(error.errorString(), QString::number(error.offset)); + return {}; + } + + file.close(); + + if (json.value("encrypted").toBool()) { + m_error = QObject::tr("Encrypted files are not supported."); + return {}; + } + + auto db = QSharedPointer::create(); + db->rootGroup()->setName(QObject::tr("Proton Pass Import")); + + writeVaultToDatabase(json, db); + + return db; +} diff --git a/src/fdosecrets/DatabaseSettingsPageFdoSecrets.h b/src/format/ProtonPassReader.h similarity index 50% rename from src/fdosecrets/DatabaseSettingsPageFdoSecrets.h rename to src/format/ProtonPassReader.h index c54f5a276..74764b890 100644 --- a/src/fdosecrets/DatabaseSettingsPageFdoSecrets.h +++ b/src/format/ProtonPassReader.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2019 Aetf + * Copyright (C) 2024 KeePassXC Team * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -15,22 +15,29 @@ * along with this program. If not, see . */ -#ifndef KEEPASSXC_DATABASESETTINGSPAGEFDOSECRETS_H -#define KEEPASSXC_DATABASESETTINGSPAGEFDOSECRETS_H +#ifndef PROTONPASS_READER_H +#define PROTONPASS_READER_H -#include "gui/dbsettings/DatabaseSettingsDialog.h" +#include -class DatabaseSettingsPageFdoSecrets : public IDatabaseSettingsPage +class Database; + +/*! + * Imports a Proton Pass vault in JSON format: https://proton.me/support/pass-export + */ +class ProtonPassReader { - Q_DISABLE_COPY(DatabaseSettingsPageFdoSecrets) public: - DatabaseSettingsPageFdoSecrets() = default; + explicit ProtonPassReader() = default; + ~ProtonPassReader() = default; - QString name() override; - QIcon icon() override; - QWidget* createWidget() override; - void loadSettings(QWidget* widget, QSharedPointer db) override; - void saveSettings(QWidget* widget) override; + QSharedPointer convert(const QString& path); + + bool hasError(); + QString errorString(); + +private: + QString m_error; }; -#endif // KEEPASSXC_DATABASESETTINGSPAGEFDOSECRETS_H +#endif // PROTONPASS_READER_H diff --git a/src/gui/AboutDialog.cpp b/src/gui/AboutDialog.cpp index 5b4d8824c..bc3960d11 100644 --- a/src/gui/AboutDialog.cpp +++ b/src/gui/AboutDialog.cpp @@ -327,9 +327,7 @@ AboutDialog::AboutDialog(QWidget* parent) m_ui->buttonBox->button(QDialogButtonBox::Close)->setDefault(true); } -AboutDialog::~AboutDialog() -{ -} +AboutDialog::~AboutDialog() = default; void AboutDialog::copyToClipboard() { diff --git a/src/gui/AboutDialog.h b/src/gui/AboutDialog.h index 9ea0dc802..645fcef92 100644 --- a/src/gui/AboutDialog.h +++ b/src/gui/AboutDialog.h @@ -32,7 +32,7 @@ class AboutDialog : public QDialog public: explicit AboutDialog(QWidget* parent = nullptr); - ~AboutDialog(); + ~AboutDialog() override; protected slots: void copyToClipboard(); diff --git a/src/gui/ActionCollection.cpp b/src/gui/ActionCollection.cpp new file mode 100644 index 000000000..3db86a899 --- /dev/null +++ b/src/gui/ActionCollection.cpp @@ -0,0 +1,119 @@ +/* + * Copyright (C) 2024 KeePassXC Team + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "ActionCollection.h" +#include "core/Config.h" + +#include + +ActionCollection* ActionCollection::instance() +{ + static ActionCollection ac; + return ∾ +} + +QList ActionCollection::actions() const +{ + return m_actions; +} + +void ActionCollection::addAction(QAction* action) +{ + if (!m_actions.contains(action)) { + m_actions << action; + } +} + +void ActionCollection::addActions(const QList& actions) +{ + for (auto a : actions) { + addAction(a); + } +} + +QKeySequence ActionCollection::defaultShortcut(const QAction* action) const +{ + auto shortcuts = defaultShortcuts(action); + return shortcuts.isEmpty() ? QKeySequence() : shortcuts.first(); +} + +QList ActionCollection::defaultShortcuts(const QAction* action) const +{ + return action->property("defaultShortcuts").value>(); +} + +void ActionCollection::setDefaultShortcut(QAction* action, const QKeySequence& shortcut) +{ + setDefaultShortcuts(action, {shortcut}); +} + +void ActionCollection::setDefaultShortcut(QAction* action, QKeySequence::StandardKey standard) +{ + if (!QKeySequence::keyBindings(standard).isEmpty()) { + setDefaultShortcuts(action, QKeySequence::keyBindings(standard)); + } +} + +void ActionCollection::setDefaultShortcuts(QAction* action, const QList& shortcuts) +{ + action->setShortcuts(shortcuts); + action->setProperty("defaultShortcuts", QVariant::fromValue(shortcuts)); +} + +void ActionCollection::restoreShortcuts() +{ + const auto shortcuts = Config::instance()->getShortcuts(); + QHash actionsByName; + for (auto action : m_actions) { + actionsByName.insert(action->objectName(), action); + } + for (const auto& shortcut : shortcuts) { + if (actionsByName.contains(shortcut.name)) { + const auto key = QKeySequence::fromString(shortcut.shortcut); + actionsByName.value(shortcut.name)->setShortcut(key); + } + } +} + +void ActionCollection::saveShortcuts() +{ + QList shortcuts; + shortcuts.reserve(m_actions.size()); + for (auto a : m_actions) { + // Only store non-default shortcut assignments + if (a->shortcut() != defaultShortcut(a)) { + shortcuts << Config::ShortcutEntry{a->objectName(), a->shortcut().toString()}; + } + } + Config::instance()->setShortcuts(shortcuts); +} + +QAction* ActionCollection::isConflictingShortcut(const QAction* action, const QKeySequence& seq) const +{ + // Empty sequences don't conflict with anything + if (seq.isEmpty()) { + return nullptr; + } + + for (auto a : m_actions) { + if (a != action && a->shortcut() == seq) { + return a; + } + } + + return nullptr; +} diff --git a/src/gui/ActionCollection.h b/src/gui/ActionCollection.h new file mode 100644 index 000000000..c9045b552 --- /dev/null +++ b/src/gui/ActionCollection.h @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2024 KeePassXC Team + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef KEEPASSXC_ACTION_COLLECTION_H +#define KEEPASSXC_ACTION_COLLECTION_H + +#include +#include +#include + +/** + * This class manages all actions that are shortcut configurable. + * It also allows you to access the actions inside it from anywhere + * in the gui code. + */ +class ActionCollection : public QObject +{ + Q_OBJECT + ActionCollection() = default; + +public: + static ActionCollection* instance(); + + QList actions() const; + + void addAction(QAction* action); + void addActions(const QList& actions); + + QKeySequence defaultShortcut(const QAction* a) const; + QList defaultShortcuts(const QAction* a) const; + + void setDefaultShortcut(QAction* a, const QKeySequence& shortcut); + void setDefaultShortcut(QAction* a, QKeySequence::StandardKey standard); + void setDefaultShortcuts(QAction* a, const QList& shortcut); + + // Check if any action conflicts with @p seq and return the conflicting action + QAction* isConflictingShortcut(const QAction* action, const QKeySequence& seq) const; + +public slots: + void restoreShortcuts(); + void saveShortcuts(); + +private: + QList m_actions; +}; + +#endif diff --git a/src/gui/Application.cpp b/src/gui/Application.cpp index 4df2bc047..01553ad91 100644 --- a/src/gui/Application.cpp +++ b/src/gui/Application.cpp @@ -35,7 +35,7 @@ #include #if defined(Q_OS_UNIX) -#include +#include #include #include #endif @@ -44,6 +44,7 @@ namespace { constexpr int WaitTimeoutMSec = 150; const char BlockSizeProperty[] = "blockSize"; + int g_OriginalFontSize = 0; } // namespace Application::Application(int& argc, char** argv) @@ -151,12 +152,7 @@ void Application::bootstrap(const QString& uiLanguage) { Bootstrap::bootstrap(uiLanguage); -#ifdef Q_OS_WIN - // Qt on Windows uses "MS Shell Dlg 2" as the default font for many widgets, which resolves - // to Tahoma 8pt, whereas the correct font would be "Segoe UI" 9pt. - // Apparently, some widgets are already using the correct font. Thanks, MuseScore for this neat fix! - QApplication::setFont(QApplication::font("QMessageBox")); -#endif + applyFontSize(); osUtils->registerNativeEventFilter(); MessageBox::initializeButtonDefs(); @@ -205,6 +201,28 @@ void Application::applyTheme() } } +void Application::applyFontSize() +{ + auto font = QApplication::font(); + + // Store the original font size on first call + if (g_OriginalFontSize <= 0) { +#ifdef Q_OS_WIN + // Qt on Windows uses "MS Shell Dlg 2" as the default font for many widgets, which resolves + // to Tahoma 8pt, whereas the correct font would be "Segoe UI" 9pt. + // Apparently, some widgets are already using the correct font. Thanks, MuseScore for this neat fix! + font = QApplication::font("QMessageBox"); +#endif + g_OriginalFontSize = font.pointSize(); + } + + // Adjust application wide default font size + auto newSize = g_OriginalFontSize + qBound(-2, config()->get(Config::GUI_FontSizeOffset).toInt(), 4); + font.setPointSize(newSize); + QApplication::setFont(font); + QApplication::setFont(font, "QWidget"); +} + bool Application::event(QEvent* event) { // Handle Apple QFileOpenEvent from finder (double click on .kdbx file) @@ -284,7 +302,7 @@ void Application::processIncomingConnection() void Application::socketReadyRead() { - QLocalSocket* socket = qobject_cast(sender()); + auto socket = qobject_cast(sender()); if (!socket) { return; } diff --git a/src/gui/Application.h b/src/gui/Application.h index 937d9d386..349c93923 100644 --- a/src/gui/Application.h +++ b/src/gui/Application.h @@ -42,6 +42,7 @@ public: ~Application() override; static void bootstrap(const QString& uiLanguage = "system"); + static void applyFontSize(); void applyTheme(); diff --git a/src/gui/ApplicationSettingsWidget.cpp b/src/gui/ApplicationSettingsWidget.cpp index 6414e6be1..8d53d6f0f 100644 --- a/src/gui/ApplicationSettingsWidget.cpp +++ b/src/gui/ApplicationSettingsWidget.cpp @@ -1,6 +1,6 @@ /* + * Copyright (C) 2023 KeePassXC Team * Copyright (C) 2012 Felix Geyer - * Copyright (C) 2017 KeePassXC Team * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -21,6 +21,7 @@ #include "ui_ApplicationSettingsWidgetSecurity.h" #include #include +#include #include "config-keepassx.h" @@ -29,14 +30,12 @@ #include "gui/Icons.h" #include "gui/MainWindow.h" #include "gui/osutils/OSUtils.h" +#include "quickunlock/QuickUnlockInterface.h" #include "FileDialog.h" #include "MessageBox.h" -#ifdef Q_OS_MACOS -#include "touchid/TouchID.h" -#endif -#ifdef Q_CC_MSVC -#include "winhello/WindowsHello.h" +#ifdef WITH_XC_BROWSER +#include "browser/BrowserSettingsPage.h" #endif class ApplicationSettingsWidget::ExtraPage @@ -101,6 +100,9 @@ ApplicationSettingsWidget::ApplicationSettingsWidget(QWidget* parent) m_generalUi->setupUi(m_generalWidget); addPage(tr("General"), icons()->icon("preferences-other"), m_generalWidget); addPage(tr("Security"), icons()->icon("security-high"), m_secWidget); +#ifdef WITH_XC_BROWSER + addSettingsPage(new BrowserSettingsPage()); +#endif if (!autoType()->isAvailable()) { m_generalUi->generalSettingsTabWidget->removeTab(1); @@ -115,6 +117,8 @@ ApplicationSettingsWidget::ApplicationSettingsWidget(QWidget* parent) connect(m_generalUi->systrayShowCheckBox, SIGNAL(toggled(bool)), SLOT(systrayToggled(bool))); connect(m_generalUi->rememberLastDatabasesCheckBox, SIGNAL(toggled(bool)), SLOT(rememberDatabasesToggled(bool))); connect(m_generalUi->resetSettingsButton, SIGNAL(clicked()), SLOT(resetSettings())); + connect(m_generalUi->importSettingsButton, SIGNAL(clicked()), SLOT(importSettings())); + connect(m_generalUi->exportSettingsButton, SIGNAL(clicked()), SLOT(exportSettings())); connect(m_generalUi->useAlternativeSaveCheckBox, SIGNAL(toggled(bool)), m_generalUi->alternativeSaveComboBox, SLOT(setEnabled(bool))); @@ -143,6 +147,22 @@ ApplicationSettingsWidget::ApplicationSettingsWidget(QWidget* parent) m_secUi->lockDatabaseMinimizeCheckBox->setEnabled(!state); }); + // Set Auto-Type shortcut when changed + connect( + m_generalUi->autoTypeShortcutWidget, &ShortcutWidget::shortcutChanged, this, [this](auto key, auto modifiers) { + QString error; + if (autoType()->registerGlobalShortcut(key, modifiers, &error)) { + m_generalUi->autoTypeShortcutWidget->setStyleSheet(""); + } else { + QToolTip::showText(mapToGlobal(rect().bottomLeft()), error); + m_generalUi->autoTypeShortcutWidget->setStyleSheet("background-color: #FF9696;"); + } + }); + connect(m_generalUi->autoTypeShortcutWidget, &ShortcutWidget::shortcutReset, this, [this] { + autoType()->unregisterGlobalShortcut(); + m_generalUi->autoTypeShortcutWidget->setStyleSheet(""); + }); + // Disable mouse wheel grab when scrolling // This prevents combo box and spinner values from changing without explicit focus auto mouseWheelFilter = new MouseWheelEventFilter(this); @@ -150,6 +170,7 @@ ApplicationSettingsWidget::ApplicationSettingsWidget(QWidget* parent) m_generalUi->toolButtonStyleComboBox->installEventFilter(mouseWheelFilter); m_generalUi->languageComboBox->installEventFilter(mouseWheelFilter); m_generalUi->trayIconAppearance->installEventFilter(mouseWheelFilter); + m_generalUi->fontSizeComboBox->installEventFilter(mouseWheelFilter); #ifdef WITH_XC_UPDATECHECK connect(m_generalUi->checkForUpdatesOnStartupCheckBox, SIGNAL(toggled(bool)), SLOT(checkUpdatesToggled(bool))); @@ -166,9 +187,7 @@ ApplicationSettingsWidget::ApplicationSettingsWidget(QWidget* parent) #endif } -ApplicationSettingsWidget::~ApplicationSettingsWidget() -{ -} +ApplicationSettingsWidget::~ApplicationSettingsWidget() = default; void ApplicationSettingsWidget::addSettingsPage(ISettingsPage* page) { @@ -207,6 +226,7 @@ void ApplicationSettingsWidget::loadSettings() m_generalUi->autoReloadOnChangeCheckBox->setChecked(config()->get(Config::AutoReloadOnChange).toBool()); m_generalUi->minimizeAfterUnlockCheckBox->setChecked(config()->get(Config::MinimizeAfterUnlock).toBool()); m_generalUi->minimizeOnOpenUrlCheckBox->setChecked(config()->get(Config::MinimizeOnOpenUrl).toBool()); + m_generalUi->openUrlOnDoubleClick->setChecked(config()->get(Config::OpenURLOnDoubleClick).toBool()); m_generalUi->hideWindowOnCopyCheckBox->setChecked(config()->get(Config::HideWindowOnCopy).toBool()); hideWindowOnCopyCheckBoxToggled(m_generalUi->hideWindowOnCopyCheckBox->isChecked()); m_generalUi->minimizeOnCopyRadioButton->setChecked(config()->get(Config::MinimizeOnCopy).toBool()); @@ -217,6 +237,10 @@ void ApplicationSettingsWidget::loadSettings() m_generalUi->autoTypeEntryURLMatchCheckBox->setChecked(config()->get(Config::AutoTypeEntryURLMatch).toBool()); m_generalUi->autoTypeHideExpiredEntryCheckBox->setChecked(config()->get(Config::AutoTypeHideExpiredEntry).toBool()); m_generalUi->faviconTimeoutSpinBox->setValue(config()->get(Config::FaviconDownloadTimeout).toInt()); + m_generalUi->ConfirmMoveEntryToRecycleBinCheckBox->setChecked( + !config()->get(Config::Security_NoConfirmMoveEntryToRecycleBin).toBool()); + m_generalUi->EnableCopyOnDoubleClickCheckBox->setChecked( + config()->get(Config::Security_EnableCopyOnDoubleClick).toBool()); m_generalUi->languageComboBox->clear(); QList> languages = Translator::availableLanguages(); @@ -228,6 +252,8 @@ void ApplicationSettingsWidget::loadSettings() m_generalUi->languageComboBox->setCurrentIndex(defaultIndex); } + m_generalUi->menubarShowCheckBox->setChecked(!config()->get(Config::GUI_HideMenubar).toBool()); + m_generalUi->toolbarShowCheckBox->setChecked(!config()->get(Config::GUI_HideToolbar).toBool()); m_generalUi->toolbarMovableCheckBox->setChecked(config()->get(Config::GUI_MovableToolbar).toBool()); m_generalUi->monospaceNotesCheckBox->setChecked(config()->get(Config::GUI_MonospaceNotes).toBool()); m_generalUi->colorPasswordsCheckBox->setChecked(config()->get(Config::GUI_ColorPasswords).toBool()); @@ -240,10 +266,25 @@ void ApplicationSettingsWidget::loadSettings() m_generalUi->toolButtonStyleComboBox->addItem(tr("Follow style"), Qt::ToolButtonFollowStyle); int toolButtonStyleIndex = m_generalUi->toolButtonStyleComboBox->findData(config()->get(Config::GUI_ToolButtonStyle)); - if (toolButtonStyleIndex > 0) { + if (toolButtonStyleIndex >= 0) { m_generalUi->toolButtonStyleComboBox->setCurrentIndex(toolButtonStyleIndex); } + m_generalUi->fontSizeComboBox->clear(); + m_generalUi->fontSizeComboBox->addItem(tr("Small"), -1); + m_generalUi->fontSizeComboBox->addItem(tr("Normal"), 0); + m_generalUi->fontSizeComboBox->addItem(tr("Medium"), 1); + m_generalUi->fontSizeComboBox->addItem(tr("Large"), 2); + + int fontSizeIndex = m_generalUi->fontSizeComboBox->findData(config()->get(Config::GUI_FontSizeOffset)); + if (fontSizeIndex >= 0) { + m_generalUi->fontSizeComboBox->setCurrentIndex(fontSizeIndex); + } else { + // Custom value entered into config file, add it to the list and select it + m_generalUi->fontSizeComboBox->addItem(tr("Custom"), config()->get(Config::GUI_FontSizeOffset).toInt()); + m_generalUi->fontSizeComboBox->setCurrentIndex(m_generalUi->fontSizeComboBox->count() - 1); + } + m_generalUi->systrayShowCheckBox->setChecked(config()->get(Config::GUI_ShowTrayIcon).toBool()); systrayToggled(m_generalUi->systrayShowCheckBox->isChecked()); m_generalUi->systrayMinimizeToTrayCheckBox->setChecked(config()->get(Config::GUI_MinimizeToTray).toBool()); @@ -301,6 +342,13 @@ void ApplicationSettingsWidget::loadSettings() && config()->get(Config::Security_LockDatabaseMinimize).toBool()); m_secUi->lockDatabaseOnScreenLockCheckBox->setChecked( config()->get(Config::Security_LockDatabaseScreenLock).toBool()); +#if defined(Q_OS_MACOS) + m_secUi->lockDatabasesOnUserSwitchCheckBox->setVisible(true); +#else + m_secUi->lockDatabasesOnUserSwitchCheckBox->setVisible(false); +#endif + m_secUi->lockDatabasesOnUserSwitchCheckBox->setChecked( + config()->get(Config::Security_LockDatabaseOnUserSwitch).toBool()); m_secUi->fallbackToSearch->setChecked(config()->get(Config::Security_IconDownloadFallback).toBool()); m_secUi->passwordsHiddenCheckBox->setChecked(config()->get(Config::Security_PasswordsHidden).toBool()); @@ -309,19 +357,8 @@ void ApplicationSettingsWidget::loadSettings() config()->get(Config::Security_HidePasswordPreviewPanel).toBool()); m_secUi->hideTotpCheckBox->setChecked(config()->get(Config::Security_HideTotpPreviewPanel).toBool()); m_secUi->hideNotesCheckBox->setChecked(config()->get(Config::Security_HideNotes).toBool()); - m_secUi->NoConfirmMoveEntryToRecycleBinCheckBox->setChecked( - config()->get(Config::Security_NoConfirmMoveEntryToRecycleBin).toBool()); - m_secUi->EnableCopyOnDoubleClickCheckBox->setChecked( - config()->get(Config::Security_EnableCopyOnDoubleClick).toBool()); - bool quickUnlockAvailable = false; -#if defined(Q_OS_MACOS) - quickUnlockAvailable = TouchID::getInstance().isAvailable(); -#elif defined(Q_CC_MSVC) - quickUnlockAvailable = getWindowsHello()->isAvailable(); - connect(getWindowsHello(), &WindowsHello::availableChanged, m_secUi->quickUnlockCheckBox, &QCheckBox::setEnabled); -#endif - m_secUi->quickUnlockCheckBox->setEnabled(quickUnlockAvailable); + m_secUi->quickUnlockCheckBox->setEnabled(getQuickUnlock()->isAvailable()); m_secUi->quickUnlockCheckBox->setChecked(config()->get(Config::Security_QuickUnlock).toBool()); for (const ExtraPage& page : asConst(m_extraPages)) { @@ -362,6 +399,7 @@ void ApplicationSettingsWidget::saveSettings() config()->set(Config::AutoReloadOnChange, m_generalUi->autoReloadOnChangeCheckBox->isChecked()); config()->set(Config::MinimizeAfterUnlock, m_generalUi->minimizeAfterUnlockCheckBox->isChecked()); config()->set(Config::MinimizeOnOpenUrl, m_generalUi->minimizeOnOpenUrlCheckBox->isChecked()); + config()->set(Config::OpenURLOnDoubleClick, m_generalUi->openUrlOnDoubleClick->isChecked()); config()->set(Config::HideWindowOnCopy, m_generalUi->hideWindowOnCopyCheckBox->isChecked()); config()->set(Config::MinimizeOnCopy, m_generalUi->minimizeOnCopyRadioButton->isChecked()); config()->set(Config::DropToBackgroundOnCopy, m_generalUi->dropToBackgroundOnCopyRadioButton->isChecked()); @@ -370,6 +408,9 @@ void ApplicationSettingsWidget::saveSettings() config()->set(Config::AutoTypeEntryURLMatch, m_generalUi->autoTypeEntryURLMatchCheckBox->isChecked()); config()->set(Config::AutoTypeHideExpiredEntry, m_generalUi->autoTypeHideExpiredEntryCheckBox->isChecked()); config()->set(Config::FaviconDownloadTimeout, m_generalUi->faviconTimeoutSpinBox->value()); + config()->set(Config::Security_NoConfirmMoveEntryToRecycleBin, + !m_generalUi->ConfirmMoveEntryToRecycleBinCheckBox->isChecked()); + config()->set(Config::Security_EnableCopyOnDoubleClick, m_generalUi->EnableCopyOnDoubleClickCheckBox->isChecked()); auto language = m_generalUi->languageComboBox->currentData().toString(); if (config()->get(Config::GUI_Language) != language) { @@ -380,11 +421,14 @@ void ApplicationSettingsWidget::saveSettings() } config()->set(Config::GUI_Language, language); + config()->set(Config::GUI_HideMenubar, !m_generalUi->menubarShowCheckBox->isChecked()); + config()->set(Config::GUI_HideToolbar, !m_generalUi->toolbarShowCheckBox->isChecked()); config()->set(Config::GUI_MovableToolbar, m_generalUi->toolbarMovableCheckBox->isChecked()); config()->set(Config::GUI_MonospaceNotes, m_generalUi->monospaceNotesCheckBox->isChecked()); config()->set(Config::GUI_ColorPasswords, m_generalUi->colorPasswordsCheckBox->isChecked()); config()->set(Config::GUI_ToolButtonStyle, m_generalUi->toolButtonStyleComboBox->currentData().toString()); + config()->set(Config::GUI_FontSizeOffset, m_generalUi->fontSizeComboBox->currentData().toInt()); config()->set(Config::GUI_ShowTrayIcon, m_generalUi->systrayShowCheckBox->isChecked()); config()->set(Config::GUI_TrayIconAppearance, m_generalUi->trayIconAppearance->currentData().toString()); @@ -421,6 +465,7 @@ void ApplicationSettingsWidget::saveSettings() config()->set(Config::Security_LockDatabaseIdleSeconds, m_secUi->lockDatabaseIdleSpinBox->value()); config()->set(Config::Security_LockDatabaseMinimize, m_secUi->lockDatabaseMinimizeCheckBox->isChecked()); config()->set(Config::Security_LockDatabaseScreenLock, m_secUi->lockDatabaseOnScreenLockCheckBox->isChecked()); + config()->set(Config::Security_LockDatabaseOnUserSwitch, m_secUi->lockDatabasesOnUserSwitchCheckBox->isChecked()); config()->set(Config::Security_IconDownloadFallback, m_secUi->fallbackToSearch->isChecked()); config()->set(Config::Security_PasswordsHidden, m_secUi->passwordsHiddenCheckBox->isChecked()); @@ -429,9 +474,6 @@ void ApplicationSettingsWidget::saveSettings() config()->set(Config::Security_HidePasswordPreviewPanel, m_secUi->passwordPreviewCleartextCheckBox->isChecked()); config()->set(Config::Security_HideTotpPreviewPanel, m_secUi->hideTotpCheckBox->isChecked()); config()->set(Config::Security_HideNotes, m_secUi->hideNotesCheckBox->isChecked()); - config()->set(Config::Security_NoConfirmMoveEntryToRecycleBin, - m_secUi->NoConfirmMoveEntryToRecycleBinCheckBox->isChecked()); - config()->set(Config::Security_EnableCopyOnDoubleClick, m_secUi->EnableCopyOnDoubleClickCheckBox->isChecked()); if (m_secUi->quickUnlockCheckBox->isEnabled()) { config()->set(Config::Security_QuickUnlock, m_secUi->quickUnlockCheckBox->isChecked()); @@ -459,8 +501,8 @@ void ApplicationSettingsWidget::resetSettings() { // Confirm reset auto ans = MessageBox::question(this, - tr("Reset Settings?"), - tr("Are you sure you want to reset all general and security settings to default?"), + tr("Confirm Reset"), + tr("Are you sure you want to reset all settings to default?"), MessageBox::Reset | MessageBox::Cancel, MessageBox::Cancel); if (ans == MessageBox::Cancel) { @@ -495,6 +537,33 @@ void ApplicationSettingsWidget::resetSettings() emit settingsReset(); } +void ApplicationSettingsWidget::importSettings() +{ + auto file = fileDialog()->getOpenFileName(this, tr("Import KeePassXC Settings"), {}, "*.ini"); + if (file.isEmpty()) { + return; + } + + if (!config()->importSettings(file)) { + showMessage(tr("Failed to import settings from %1, not a valid settings file.").arg(file), + MessageWidget::Error); + return; + } + + loadSettings(); + emit settingsReset(); +} + +void ApplicationSettingsWidget::exportSettings() +{ + auto file = fileDialog()->getSaveFileName(this, tr("Export KeePassXC Settings"), {}, "*.ini"); + if (file.isEmpty()) { + return; + } + + config()->exportSettings(file); +} + void ApplicationSettingsWidget::reject() { // register the old key again as it might have changed @@ -557,4 +626,4 @@ void ApplicationSettingsWidget::selectBackupDirectory() m_generalUi->backupFilePath->setText( QDir(backupDirectory).filePath(config()->getDefault(Config::BackupFilePathPattern).toString())); } -} \ No newline at end of file +} diff --git a/src/gui/ApplicationSettingsWidget.h b/src/gui/ApplicationSettingsWidget.h index 15fc5a344..7e43196b1 100644 --- a/src/gui/ApplicationSettingsWidget.h +++ b/src/gui/ApplicationSettingsWidget.h @@ -30,9 +30,7 @@ namespace Ui class ISettingsPage { public: - virtual ~ISettingsPage() - { - } + virtual ~ISettingsPage() = default; virtual QString name() = 0; virtual QIcon icon() = 0; virtual QWidget* createWidget() = 0; @@ -46,7 +44,7 @@ class ApplicationSettingsWidget : public EditWidget public: explicit ApplicationSettingsWidget(QWidget* parent = nullptr); - ~ApplicationSettingsWidget(); + ~ApplicationSettingsWidget() override; void addSettingsPage(ISettingsPage* page); void loadSettings(); @@ -56,6 +54,8 @@ signals: private slots: void saveSettings(); void resetSettings(); + void importSettings(); + void exportSettings(); void reject(); void autoSaveToggled(bool checked); void hideWindowOnCopyCheckBoxToggled(bool checked); diff --git a/src/gui/ApplicationSettingsWidgetGeneral.ui b/src/gui/ApplicationSettingsWidgetGeneral.ui index 0270c52d2..eb69f2615 100644 --- a/src/gui/ApplicationSettingsWidgetGeneral.ui +++ b/src/gui/ApplicationSettingsWidgetGeneral.ui @@ -58,8 +58,8 @@ 0 0 - 564 - 930 + 568 + 1202
    @@ -268,58 +268,46 @@
    - - - QLayout::SetMaximumSize - + 6 - + + QLayout::SetMaximumSize + + - On database unlock, show entries that + On database unlock, show entries that will expire within - + true - - - 0 - 0 - - Qt::StrongFocus - On database unlock, show entries that - - - have expired + On database unlock, show entries that will expire within - days - - - will expire within + days 0 - 30 + 90 - 0 + 3 - + Qt::Horizontal @@ -380,6 +368,25 @@ + + 0 + + + + + Qt::Horizontal + + + QSizePolicy::Fixed + + + + 30 + 20 + + + + @@ -389,41 +396,70 @@ - Backup destination + Destination format: backupFilePath + + + + Qt::Horizontal + + + QSizePolicy::Fixed + + + + 6 + 20 + + + + false - Specifies the database backup file location. Occurrences of "{DB_FILENAME}" are replaced with the filename of the saved database without extension. {TIME:<format>} is replaced with the backup time, see https://doc.qt.io/qt-5/qdatetime.html#toString. <format> defaults to format string "dd_MM_yyyy_hh-mm-ss". + <html><head/><body><p><span style=" font-weight:600;">{DB_FILENAME}</span> is replaced with the filename of the saved database without extension</p><p><span style=" font-weight:600;">{TIME:&lt;format&gt;}</span> is replaced with the specified time format (default: dd_MM_yyyy_hh-mm-ss)</p><p>See the User Guide for more details</p></body></html> {DB_FILENAME}.old.kdbx + + + + Qt::Horizontal + + + QSizePolicy::Fixed + + + + 6 + 20 + + + + false - Choose... + Choose folder... - - - @@ -457,6 +493,9 @@ false + + QComboBox::AdjustToContents + Temporary file moved into place @@ -493,6 +532,30 @@ Entry Management + + + + Show confirmation before moving entries to recycle bin + + + + + + + Copy data on double clicking field in entry view + + + + + + + Open browser on double clicking URL field in entry view + + + true + + + @@ -649,56 +712,18 @@ 10 - - - - - 0 - 0 - + + + + Qt::Horizontal - - Qt::StrongFocus + + + 40 + 20 + - - Toolbar button style - - - QComboBox::AdjustToContents - - - - - - - true - - - - 0 - 0 - - - - Movable toolbar - - - - - - - - 0 - 0 - - - - Qt::StrongFocus - - - Language selection - - + @@ -719,25 +744,59 @@ - - + + + + true + + + + 0 + 0 + + - (restart program to activate) + Movable toolbar - - - - Qt::Horizontal + + + + + 0 + 0 + - - - 40 - 20 - + + Qt::StrongFocus - + + Toolbar button style + + + QComboBox::AdjustToContents + + + + + + + + 0 + 0 + + + + Qt::StrongFocus + + + Language selection + + + QComboBox::AdjustToContents + + @@ -750,9 +809,6 @@ 0 - - margin-right: 5px - Toolbar button style: @@ -764,8 +820,58 @@ + + + + (restart program to activate) + + + + + + + Font size: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + fontSizeComboBox + + + + + + + Qt::StrongFocus + + + Font size selection + + + QComboBox::AdjustToContents + + + + + + + Show toolbar + + + + + + + Show the menu bar by pressing the Alt key + + + Show menubar + + + @@ -835,6 +941,9 @@ Tray icon type + + QComboBox::AdjustToContents + @@ -947,7 +1056,7 @@ - 0 + 6 QLayout::SetMaximumSize @@ -960,21 +1069,32 @@ - + Qt::Horizontal - - QSizePolicy::Expanding - - 50 + 40 20 + + + + Import settings… + + + + + + + Export settings… + + +
    @@ -1244,7 +1364,7 @@ ShortcutWidget QLineEdit -
    autotype/ShortcutWidget.h
    +
    gui/widgets/ShortcutWidget.h
    @@ -1271,6 +1391,9 @@ backupFilePathPicker useAlternativeSaveCheckBox alternativeSaveComboBox + ConfirmMoveEntryToRecycleBinCheckBox + EnableCopyOnDoubleClickCheckBox + openUrlOnDoubleClick useGroupIconOnEntryCreationCheckBox minimizeOnOpenUrlCheckBox hideWindowOnCopyCheckBox @@ -1280,12 +1403,17 @@ languageComboBox toolButtonStyleComboBox toolbarMovableCheckBox + toolbarShowCheckBox + menubarShowCheckBox + colorPasswordsCheckBox monospaceNotesCheckBox minimizeOnCloseCheckBox systrayShowCheckBox trayIconAppearance systrayMinimizeToTrayCheckBox resetSettingsButton + importSettingsButton + exportSettingsButton autoTypeEntryTitleMatchCheckBox autoTypeEntryURLMatchCheckBox autoTypeAskCheckBox diff --git a/src/gui/ApplicationSettingsWidgetSecurity.ui b/src/gui/ApplicationSettingsWidgetSecurity.ui index 152f659ff..c4cb0e01f 100644 --- a/src/gui/ApplicationSettingsWidgetSecurity.ui +++ b/src/gui/ApplicationSettingsWidgetSecurity.ui @@ -7,7 +7,7 @@ 0 0 364 - 493 + 505 @@ -31,7 +31,7 @@ Timeouts - + @@ -160,11 +160,11 @@ - + - Convenience + Lock Options - + @@ -179,6 +179,13 @@ + + + + Lock databases when switching user + + + @@ -186,6 +193,22 @@ + + + + + + + Convenience + + + + + + Use placeholder for empty password fields + + + @@ -193,13 +216,6 @@ - - - - Use placeholder for empty password fields - - - @@ -217,21 +233,7 @@ - Hide entry notes by default - - - - - - - Move entries to recycle bin without confirmation - - - - - - - Enable double click to copy the username/password entry columns + Hide notes in the entry preview panel @@ -279,11 +281,14 @@ lockDatabaseIdleSpinBox clearSearchCheckBox clearSearchSpinBox + quickUnlockCheckBox lockDatabaseOnScreenLockCheckBox + lockDatabasesOnUserSwitchCheckBox lockDatabaseMinimizeCheckBox - passwordsHiddenCheckBox passwordShowDotsCheckBox + passwordsHiddenCheckBox passwordPreviewCleartextCheckBox + hideTotpCheckBox hideNotesCheckBox fallbackToSearch diff --git a/src/gui/CategoryListWidget.cpp b/src/gui/CategoryListWidget.cpp index 3145fbe25..cae806f62 100644 --- a/src/gui/CategoryListWidget.cpp +++ b/src/gui/CategoryListWidget.cpp @@ -43,9 +43,7 @@ CategoryListWidget::CategoryListWidget(QWidget* parent) // clang-format on } -CategoryListWidget::~CategoryListWidget() -{ -} +CategoryListWidget::~CategoryListWidget() = default; QSize CategoryListWidget::sizeHint() const { @@ -64,13 +62,13 @@ QSize CategoryListWidget::sizeHint() const QSize CategoryListWidget::minimumSizeHint() const { - return QSize(m_itemDelegate->minWidth() + m_ui->categoryList->frameWidth() * 2, - m_ui->categoryList->sizeHintForRow(0) * 2); + return {m_itemDelegate->minWidth() + m_ui->categoryList->frameWidth() * 2, + m_ui->categoryList->sizeHintForRow(0) * 2}; } int CategoryListWidget::addCategory(const QString& labelText, const QIcon& icon) { - QListWidgetItem* item = new QListWidgetItem(m_ui->categoryList); + auto item = new QListWidgetItem(m_ui->categoryList); item->setText(labelText); item->setIcon(icon); m_ui->categoryList->addItem(item); diff --git a/src/gui/CategoryListWidget.h b/src/gui/CategoryListWidget.h index cbf0ef0eb..aa182fa48 100644 --- a/src/gui/CategoryListWidget.h +++ b/src/gui/CategoryListWidget.h @@ -35,7 +35,7 @@ class CategoryListWidget : public QWidget public: CategoryListWidget(QWidget* parent = nullptr); - ~CategoryListWidget(); + ~CategoryListWidget() override; int currentCategory(); void setCurrentCategory(int index); diff --git a/src/gui/Clipboard.cpp b/src/gui/Clipboard.cpp index f43d7197b..1c699f67e 100644 --- a/src/gui/Clipboard.cpp +++ b/src/gui/Clipboard.cpp @@ -60,6 +60,8 @@ void Clipboard::setText(const QString& text, bool clear) mime->setData("x-kde-passwordManagerHint", QByteArrayLiteral("secret")); #elif defined(Q_OS_WIN) mime->setData("ExcludeClipboardContentFromMonitorProcessing", QByteArrayLiteral("1")); + mime->setData("CanIncludeInClipboardHistory", {4, '\0'}); + mime->setData("CanUploadToCloudClipboard ", {4, '\0'}); #endif if (clipboard->supportsSelection()) { diff --git a/src/gui/Clipboard.h b/src/gui/Clipboard.h index 4dc2f3127..147b65aff 100644 --- a/src/gui/Clipboard.h +++ b/src/gui/Clipboard.h @@ -22,7 +22,7 @@ #include #include #ifdef Q_OS_MACOS -#include "core/MacPasteboard.h" +#include "gui/osutils/macutils/MacPasteboard.h" #include #endif diff --git a/src/gui/CloneDialog.cpp b/src/gui/CloneDialog.cpp index 72199ae5a..3e3c85347 100644 --- a/src/gui/CloneDialog.cpp +++ b/src/gui/CloneDialog.cpp @@ -29,11 +29,7 @@ CloneDialog::CloneDialog(DatabaseWidget* parent, Database* db, Entry* entry) m_ui->setupUi(this); window()->layout()->setSizeConstraint(QLayout::SetFixedSize); -#if QT_VERSION >= QT_VERSION_CHECK(5, 9, 0) setWindowFlag(Qt::WindowContextHelpButtonHint, false); -#else - setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint); -#endif setAttribute(Qt::WA_DeleteOnClose); connect(m_ui->buttonBox, SIGNAL(rejected()), SLOT(close())); @@ -64,6 +60,4 @@ void CloneDialog::cloneEntry() close(); } -CloneDialog::~CloneDialog() -{ -} +CloneDialog::~CloneDialog() = default; diff --git a/src/gui/CloneDialog.h b/src/gui/CloneDialog.h index 649ab1d5f..8e76a8d10 100644 --- a/src/gui/CloneDialog.h +++ b/src/gui/CloneDialog.h @@ -34,7 +34,7 @@ class CloneDialog : public QDialog public: explicit CloneDialog(DatabaseWidget* parent = nullptr, Database* db = nullptr, Entry* entry = nullptr); - ~CloneDialog(); + ~CloneDialog() override; signals: void entryCloned(Entry* clone); diff --git a/src/gui/DatabaseOpenDialog.cpp b/src/gui/DatabaseOpenDialog.cpp index 25c0fd25e..881db4087 100644 --- a/src/gui/DatabaseOpenDialog.cpp +++ b/src/gui/DatabaseOpenDialog.cpp @@ -36,11 +36,7 @@ DatabaseOpenDialog::DatabaseOpenDialog(QWidget* parent) { setWindowTitle(tr("Unlock Database - KeePassXC")); setWindowFlags(Qt::Dialog); -#if QT_VERSION >= QT_VERSION_CHECK(5, 9, 0) setWindowFlag(Qt::WindowContextHelpButtonHint, false); -#else - setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint); -#endif #ifdef Q_OS_LINUX // Linux requires this to overcome some Desktop Environments (also no Quick Unlock) setWindowFlags(windowFlags() | Qt::WindowStaysOnTopHint); @@ -87,7 +83,7 @@ DatabaseOpenDialog::DatabaseOpenDialog(QWidget* parent) void DatabaseOpenDialog::showEvent(QShowEvent* event) { QDialog::showEvent(event); - QTimer::singleShot(100, this, [=] { + QTimer::singleShot(100, this, [this] { if (m_view->isOnQuickUnlockScreen() && !m_view->unlockingDatabase()) { m_view->triggerQuickUnlock(); } @@ -196,22 +192,52 @@ void DatabaseOpenDialog::clearForms() m_tabBar->blockSignals(false); } +void DatabaseOpenDialog::showMessage(const QString& text, MessageWidget::MessageType type, int autoHideTimeout) +{ + m_view->showMessage(text, type, autoHideTimeout); +} + QSharedPointer DatabaseOpenDialog::database() const { return m_db; } +void DatabaseOpenDialog::done(int result) +{ + hide(); + + emit dialogFinished(result == QDialog::Accepted, m_currentDbWidget); + clearForms(); + + QDialog::done(result); + +#if QT_VERSION < QT_VERSION_CHECK(6, 3, 0) + // CDialogs are not really closed, just hidden, pre Qt 6.3? + if (testAttribute(Qt::WA_DeleteOnClose)) { + setAttribute(Qt::WA_DeleteOnClose, false); + deleteLater(); + } +#endif +} + void DatabaseOpenDialog::complete(bool accepted) { // save DB, since DatabaseOpenWidget will reset its data after accept() is called m_db = m_view->database(); + if (m_db && m_intent == Intent::RemoteSync) { + m_db->markAsTemporaryDatabase(); + } if (accepted) { accept(); } else { reject(); } - - emit dialogFinished(accepted, m_currentDbWidget); - clearForms(); +} + +void DatabaseOpenDialog::closeEvent(QCloseEvent* e) +{ + emit dialogFinished(false, m_currentDbWidget); + clearForms(); + QDialog::closeEvent(e); } diff --git a/src/gui/DatabaseOpenDialog.h b/src/gui/DatabaseOpenDialog.h index b1a59b59a..ba6fcb4e8 100644 --- a/src/gui/DatabaseOpenDialog.h +++ b/src/gui/DatabaseOpenDialog.h @@ -19,6 +19,7 @@ #define KEEPASSX_UNLOCKDATABASEDIALOG_H #include "core/Global.h" +#include "gui/MessageWidget.h" #include #include @@ -39,6 +40,7 @@ public: None, AutoType, Merge, + RemoteSync, Browser }; @@ -50,11 +52,13 @@ public: Intent intent() const; QSharedPointer database() const; void clearForms(); + void showMessage(const QString& text, MessageWidget::MessageType type, int autoHideTimeout); signals: void dialogFinished(bool accepted, DatabaseWidget* dbWidget); public slots: + void done(int result) override; void complete(bool accepted); void tabChanged(int index); @@ -62,6 +66,7 @@ protected: void showEvent(QShowEvent* event) override; private: + void closeEvent(QCloseEvent* e) override; void selectTabOffset(int offset); QPointer m_view; diff --git a/src/gui/DatabaseOpenWidget.cpp b/src/gui/DatabaseOpenWidget.cpp index b93bbd9ac..7cf5dcb15 100644 --- a/src/gui/DatabaseOpenWidget.cpp +++ b/src/gui/DatabaseOpenWidget.cpp @@ -28,13 +28,7 @@ #ifdef WITH_XC_YUBIKEY #include "keys/drivers/YubiKeyInterfaceUSB.h" #endif - -#ifdef Q_OS_MACOS -#include "touchid/TouchID.h" -#endif -#ifdef Q_CC_MSVC -#include "winhello/WindowsHello.h" -#endif +#include "quickunlock/QuickUnlockInterface.h" #include #include @@ -48,11 +42,7 @@ namespace bool isQuickUnlockAvailable() { if (config()->get(Config::Security_QuickUnlock).toBool()) { -#if defined(Q_CC_MSVC) - return getWindowsHello()->isAvailable(); -#elif defined(Q_OS_MACOS) - return TouchID::getInstance().isAvailable(); -#endif + return getQuickUnlock()->isAvailable(); } return false; } @@ -82,7 +72,6 @@ DatabaseOpenWidget::DatabaseOpenWidget(QWidget* parent) font.setPointSize(font.pointSize() + 4); font.setBold(true); m_ui->labelHeadline->setFont(font); - m_ui->labelHeadline->setText(tr("Unlock KeePassXC Database")); m_ui->quickUnlockButton->setFont(font); m_ui->quickUnlockButton->setIcon( @@ -113,7 +102,7 @@ DatabaseOpenWidget::DatabaseOpenWidget(QWidget* parent) m_ui->hardwareKeyProgress->setSizePolicy(sp); #ifdef WITH_XC_YUBIKEY - connect(m_deviceListener, SIGNAL(devicePlugged(bool, void*, void*)), this, SLOT(pollHardwareKey())); + connect(m_deviceListener, &DeviceListener::devicePlugged, this, [this] { pollHardwareKey(false, 500); }); connect(YubiKey::instance(), SIGNAL(detectComplete(bool)), SLOT(hardwareKeyResponse(bool)), Qt::QueuedConnection); connect(YubiKey::instance(), &YubiKey::userInteractionRequest, this, [this] { @@ -144,16 +133,19 @@ DatabaseOpenWidget::DatabaseOpenWidget(QWidget* parent) m_ui->resetQuickUnlockButton->setShortcut(Qt::Key_Escape); } -DatabaseOpenWidget::~DatabaseOpenWidget() -{ -} +DatabaseOpenWidget::~DatabaseOpenWidget() = default; void DatabaseOpenWidget::toggleHardwareKeyComponent(bool state) { m_ui->hardwareKeyProgress->setVisible(false); m_ui->hardwareKeyComponent->setVisible(state); m_ui->hardwareKeyCombo->setVisible(state && m_ui->hardwareKeyCombo->count() != 1); + m_ui->noHardwareKeysFoundLabel->setVisible(!state && m_manualHardwareKeyRefresh); + m_ui->noHardwareKeysFoundLabel->setText(YubiKey::instance()->connectedKeys() > 0 + ? tr("Hardware keys found, but no slots are configured.") + : tr("No hardware keys found.")); + if (!state) { m_ui->useHardwareKeyCheckBox->setChecked(false); } @@ -167,6 +159,29 @@ void DatabaseOpenWidget::toggleHardwareKeyComponent(bool state) m_ui->useHardwareKeyCheckBox->setText(tr("Use hardware key")); } } +void DatabaseOpenWidget::closeDatabase() +{ + int closeWarningInterval = 3000; + + if (!m_triedToQuit && window() == getMainWindow()) { + m_triedToQuit = true; + m_ui->messageWidget->showMessage( + tr("Press ESC again to close this database"), MessageWidget::Warning, closeWarningInterval); + + QTimer::singleShot(closeWarningInterval, this, [this]() { m_triedToQuit = false; }); + return; + } + reject(); +} + +void DatabaseOpenWidget::keyPressEvent(QKeyEvent* event) +{ + if (event->key() == Qt::Key_Escape) { + closeDatabase(); + } else { + DialogyWidget::keyPressEvent(event); + } +} bool DatabaseOpenWidget::event(QEvent* event) { @@ -197,6 +212,9 @@ bool DatabaseOpenWidget::event(QEvent* event) m_deviceListener->registerHotplugCallback(true, true, YubiKeyInterfaceUSB::ONLYKEY_USB_VID); #endif #endif + } + + if (isVisible()) { m_hideTimer.stop(); pollHardwareKey(); } @@ -225,13 +243,49 @@ bool DatabaseOpenWidget::unlockingDatabase() return m_unlockingDatabase; } +void DatabaseOpenWidget::showMessage(const QString& text, MessageWidget::MessageType type, int autoHideTimeout) +{ + m_ui->messageWidget->showMessage(text, type, autoHideTimeout); +} + void DatabaseOpenWidget::load(const QString& filename) { clearForms(); m_filename = filename; + + // Read public headers + QString error; + m_db.reset(new Database()); + m_db->open(m_filename, nullptr, &error); + m_ui->fileNameLabel->setRawText(m_filename); + // Set the public name if defined + auto label = tr("Unlock KeePassXC Database"); + if (!m_db->publicName().isEmpty()) { + label.append(QString(": %1").arg(m_db->publicName())); + } + m_ui->labelHeadline->setText(label); + + // Apply the public color to the central unlock stack if defined + auto color = m_db->publicColor(); + if (!color.isEmpty()) { + m_ui->centralStack->setStyleSheet(QString("QStackedWidget {border: 4px solid %1}").arg(color)); + } else { + m_ui->centralStack->setStyleSheet(""); + } + + // Show the database icon if defined + auto iconIndex = m_db->publicIcon(); + if (iconIndex >= 0 && iconIndex < databaseIcons()->count()) { + m_ui->dbIconLabel->setPixmap(databaseIcons()->icon(iconIndex, IconSize::Large)); + m_ui->dbIconLabel->setVisible(true); + } else { + m_ui->dbIconLabel->setPixmap({}); + m_ui->dbIconLabel->setVisible(false); + } + if (config()->get(Config::RememberLastKeyFiles).toBool()) { auto lastKeyFiles = config()->get(Config::LastKeyFiles).toHash(); if (lastKeyFiles.contains(m_filename)) { @@ -256,6 +310,7 @@ void DatabaseOpenWidget::clearForms() m_ui->keyFileLineEdit->setShowPassword(false); m_ui->keyFileLineEdit->setClearButtonEnabled(true); m_ui->hardwareKeyCombo->clear(); + toggleHardwareKeyComponent(false); toggleQuickUnlockScreen(); m_db.reset(new Database(m_filename)); @@ -273,6 +328,11 @@ QString DatabaseOpenWidget::filename() void DatabaseOpenWidget::enterKey(const QString& pw, const QString& keyFile) { + if (unlockingDatabase()) { + qWarning("Ignoring unlock request for %s because of running unlock action.", qPrintable(m_filename)); + return; + } + m_ui->editPassword->setText(pw); m_ui->keyFileLineEdit->setText(keyFile); m_blockQuickUnlock = true; @@ -318,6 +378,8 @@ void DatabaseOpenWidget::openDatabase() msgBox->exec(); if (msgBox->clickedButton() != btn) { m_db.reset(new Database()); + m_db->open(m_filename, nullptr, &error); + m_ui->messageWidget->showMessage(tr("Database unlock canceled."), MessageWidget::MessageType::Error); setUserInteractionLock(false); return; @@ -327,17 +389,7 @@ void DatabaseOpenWidget::openDatabase() // Save Quick Unlock credentials if available if (!blockQuickUnlock && isQuickUnlockAvailable()) { auto keyData = databaseKey->serialize(); -#if defined(Q_CC_MSVC) - // Store the password using Windows Hello - if (!getWindowsHello()->storeKey(m_filename, keyData)) { - getMainWindow()->displayTabMessage( - tr("Windows Hello setup was canceled or failed. Quick unlock has not been enabled."), - MessageWidget::MessageType::Warning); - } -#elif defined(Q_OS_MACOS) - // Store the password using TouchID - TouchID::getInstance().storeKey(m_filename, keyData); -#endif + getQuickUnlock()->setKey(m_db->publicUuid(), keyData); m_ui->messageWidget->hideMessage(); } @@ -385,24 +437,12 @@ QSharedPointer DatabaseOpenWidget::buildDatabaseKey() if (!m_db.isNull() && canPerformQuickUnlock()) { // try to retrieve the stored password using Windows Hello QByteArray keyData; -#ifdef Q_CC_MSVC - if (!getWindowsHello()->getKey(m_filename, keyData)) { - // Failed to retrieve Quick Unlock data - auto error = getWindowsHello()->errorString(); - if (!error.isEmpty()) { - m_ui->messageWidget->showMessage(tr("Failed to authenticate with Windows Hello: %1").arg(error), - MessageWidget::Error); - resetQuickUnlock(); - } + if (!getQuickUnlock()->getKey(m_db->publicUuid(), keyData)) { + m_ui->messageWidget->showMessage( + tr("Failed to authenticate with Quick Unlock: %1").arg(getQuickUnlock()->errorString()), + MessageWidget::Error); return {}; } -#elif defined(Q_OS_MACOS) - if (!TouchID::getInstance().getKey(m_filename, keyData)) { - // Failed to retrieve Quick Unlock data - m_ui->messageWidget->showMessage(tr("Failed to authenticate with Touch ID"), MessageWidget::Error); - return {}; - } -#endif databaseKey->setRawKey(keyData); return databaseKey; } @@ -513,27 +553,26 @@ bool DatabaseOpenWidget::browseKeyFile() return true; } -void DatabaseOpenWidget::pollHardwareKey(bool manualTrigger) +void DatabaseOpenWidget::pollHardwareKey(bool manualTrigger, int delay) { if (m_pollingHardwareKey) { return; } m_ui->hardwareKeyCombo->setEnabled(false); + m_ui->useHardwareKeyCheckBox->setEnabled(false); m_ui->hardwareKeyProgress->setVisible(true); m_ui->refreshHardwareKeys->setEnabled(false); m_ui->noHardwareKeysFoundLabel->setVisible(false); m_pollingHardwareKey = true; m_manualHardwareKeyRefresh = manualTrigger; - // Add a delay, if this is an automatic trigger, to allow the USB device to settle as - // the device may not report a valid serial number immediately after plugging in - int delay = manualTrigger ? 0 : 500; QTimer::singleShot(delay, this, [] { YubiKey::instance()->findValidKeysAsync(); }); } void DatabaseOpenWidget::hardwareKeyResponse(bool found) { + m_ui->useHardwareKeyCheckBox->setEnabled(true); m_ui->hardwareKeyProgress->setVisible(false); m_ui->refreshHardwareKeys->setEnabled(true); m_ui->hardwareKeyCombo->clear(); @@ -590,14 +629,7 @@ void DatabaseOpenWidget::setUserInteractionLock(bool state) bool DatabaseOpenWidget::canPerformQuickUnlock() const { - if (!m_db.isNull() && isQuickUnlockAvailable()) { -#if defined(Q_CC_MSVC) - return getWindowsHello()->hasKey(m_filename); -#elif defined(Q_OS_MACOS) - return TouchID::getInstance().containsKey(m_filename); -#endif - } - return false; + return !m_db.isNull() && isQuickUnlockAvailable() && getQuickUnlock()->hasKey(m_db->publicUuid()); } bool DatabaseOpenWidget::isOnQuickUnlockScreen() const @@ -636,10 +668,11 @@ void DatabaseOpenWidget::triggerQuickUnlock() */ void DatabaseOpenWidget::resetQuickUnlock() { -#if defined(Q_CC_MSVC) - getWindowsHello()->reset(m_filename); -#elif defined(Q_OS_MACOS) - TouchID::getInstance().reset(m_filename); -#endif + if (!isQuickUnlockAvailable()) { + return; + } + if (!m_db.isNull()) { + getQuickUnlock()->reset(m_db->publicUuid()); + } load(m_filename); } diff --git a/src/gui/DatabaseOpenWidget.h b/src/gui/DatabaseOpenWidget.h index 5b7feffd2..d730634b3 100644 --- a/src/gui/DatabaseOpenWidget.h +++ b/src/gui/DatabaseOpenWidget.h @@ -25,6 +25,7 @@ #include "config-keepassx.h" #include "gui/DialogyWidget.h" +#include "gui/MessageWidget.h" #ifdef WITH_XC_YUBIKEY #include "osutils/DeviceListener.h" #endif @@ -44,13 +45,14 @@ class DatabaseOpenWidget : public DialogyWidget public: explicit DatabaseOpenWidget(QWidget* parent = nullptr); - ~DatabaseOpenWidget(); + ~DatabaseOpenWidget() override; void load(const QString& filename); QString filename(); void clearForms(); void enterKey(const QString& pw, const QString& keyFile); QSharedPointer database(); bool unlockingDatabase(); + void showMessage(const QString& text, MessageWidget::MessageType type, int autoHideTimeout); // Quick Unlock helper functions bool canPerformQuickUnlock() const; @@ -64,6 +66,7 @@ signals: protected: bool event(QEvent* event) override; + void keyPressEvent(QKeyEvent* event) override; QSharedPointer buildDatabaseKey(); void setUserInteractionLock(bool state); @@ -79,7 +82,8 @@ protected slots: private slots: bool browseKeyFile(); void toggleHardwareKeyComponent(bool state); - void pollHardwareKey(bool manualTrigger = false); + void closeDatabase(); + void pollHardwareKey(bool manualTrigger = false, int delay = 0); void hardwareKeyResponse(bool found); private: @@ -90,6 +94,7 @@ private: bool m_manualHardwareKeyRefresh = false; bool m_blockQuickUnlock = false; bool m_unlockingDatabase = false; + bool m_triedToQuit = false; QTimer m_hideTimer; QTimer m_hideNoHardwareKeysFoundTimer; diff --git a/src/gui/DatabaseOpenWidget.ui b/src/gui/DatabaseOpenWidget.ui index 104ca1959..1ef04a528 100644 --- a/src/gui/DatabaseOpenWidget.ui +++ b/src/gui/DatabaseOpenWidget.ui @@ -55,17 +55,54 @@
    - - - - 12 - true - + + + 9 - - Unlock KeePassXC Database - - + + + + + 32 + 32 + + + + + + + true + + + + + + + + 12 + 75 + true + + + + Unlock KeePassXC Database + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + @@ -143,7 +180,7 @@ 0 - 0 + 10 @@ -155,7 +192,7 @@ - 0 + 2 @@ -213,13 +250,13 @@ 0 - 10 + 0 0 - 15 + 10 @@ -362,7 +399,7 @@ 40 - 0 + 20 @@ -417,19 +454,6 @@ - - - - Qt::Vertical - - - - 0 - 5 - - - - @@ -511,6 +535,7 @@ 10 + 75 true diff --git a/src/gui/DatabaseTabWidget.cpp b/src/gui/DatabaseTabWidget.cpp index 412bc95e4..c8639eb44 100644 --- a/src/gui/DatabaseTabWidget.cpp +++ b/src/gui/DatabaseTabWidget.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2023 KeePassXC Team + * Copyright (C) 2024 KeePassXC Team * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -25,6 +25,7 @@ #include "core/Tools.h" #include "format/CsvExporter.h" #include "gui/Clipboard.h" +#include "gui/DatabaseIcons.h" #include "gui/DatabaseOpenDialog.h" #include "gui/DatabaseWidget.h" #include "gui/DatabaseWidgetStateSync.h" @@ -35,13 +36,13 @@ #include "gui/osutils/macutils/MacUtils.h" #endif #include "gui/wizard/NewDatabaseWizard.h" -#include "wizard/ImportWizard.h" DatabaseTabWidget::DatabaseTabWidget(QWidget* parent) : QTabWidget(parent) , m_dbWidgetStateSync(new DatabaseWidgetStateSync(this)) , m_dbWidgetPendingLock(nullptr) , m_databaseOpenDialog(new DatabaseOpenDialog(this)) + , m_importWizard(nullptr) , m_databaseOpenInProgress(false) { auto* tabBar = new QTabBar(this); @@ -63,16 +64,14 @@ DatabaseTabWidget::DatabaseTabWidget(QWidget* parent) // clang-format on #ifdef Q_OS_MACOS - connect(macUtils(), SIGNAL(lockDatabases()), SLOT(lockDatabases())); + connect(macUtils(), SIGNAL(userSwitched()), SLOT(lockDatabasesOnUserSwitch())); #endif m_lockDelayTimer.setSingleShot(true); connect(&m_lockDelayTimer, &QTimer::timeout, this, [this] { lockDatabases(); }); } -DatabaseTabWidget::~DatabaseTabWidget() -{ -} +DatabaseTabWidget::~DatabaseTabWidget() = default; void DatabaseTabWidget::toggleTabbar() { @@ -186,7 +185,7 @@ void DatabaseTabWidget::addDatabaseTab(const QString& filePath, auto* dbWidget = new DatabaseWidget(QSharedPointer::create(cleanFilePath), this); addDatabaseTab(dbWidget, inBackground); dbWidget->performUnlockDatabase(password, keyfile); - updateLastDatabases(cleanFilePath); + updateLastDatabases(dbWidget->database()); } /** @@ -251,55 +250,74 @@ void DatabaseTabWidget::addDatabaseTab(DatabaseWidget* dbWidget, bool inBackgrou connect(dbWidget, SIGNAL(databaseUnlocked()), SLOT(emitDatabaseLockChanged())); connect(dbWidget, SIGNAL(databaseLocked()), SLOT(updateTabName())); connect(dbWidget, SIGNAL(databaseLocked()), SLOT(emitDatabaseLockChanged())); + connect(dbWidget, + &DatabaseWidget::unlockDatabaseInDialogForSync, + this, + &DatabaseTabWidget::unlockDatabaseInDialogForSync); } -DatabaseWidget* DatabaseTabWidget::importFile() +void DatabaseTabWidget::importFile() { // Show the import wizard - QScopedPointer wizard(new ImportWizard(this)); - if (!wizard->exec()) { - return nullptr; - } + m_importWizard = new ImportWizard(this); - auto db = wizard->database(); - if (!db) { - // Import wizard was cancelled - return nullptr; - } - - auto importInto = wizard->importInto(); - if (importInto.first.isNull()) { - // Start the new database wizard with the imported database - auto newDb = execNewDatabaseWizard(); - if (newDb) { - // Merge the imported db into the new one - Merger merger(db.data(), newDb.data()); - merger.setSkipDatabaseCustomData(true); - merger.merge(); - // Show the new database - auto dbWidget = new DatabaseWidget(newDb, this); - addDatabaseTab(dbWidget); - newDb->markAsModified(); - return dbWidget; + connect(m_importWizard.data(), &QWizard::finished, [&](int result) { + if (result != QDialog::Accepted) { + return; } - } else { - for (int i = 0, c = count(); i < c; ++i) { - // Find the database and group to import into based on import wizard choice - auto dbWidget = databaseWidgetFromIndex(i); - if (!dbWidget->isLocked() && dbWidget->database()->uuid() == importInto.first) { - auto group = dbWidget->database()->rootGroup()->findGroupByUuid(importInto.second); - if (group) { - // Extract the root group from the import database - auto importGroup = db->setRootGroup(new Group()); - importGroup->setParent(group); - setCurrentIndex(i); - return dbWidget; + + auto db = m_importWizard->database(); + if (!db) { + // Import wizard was cancelled + return; + } + + switch (m_importWizard->importIntoType()) { + case ImportWizard::EXISTING_DATABASE: + for (int i = 0, c = count(); i < c; ++i) { + auto importInto = m_importWizard->importInto(); + // Find the database and group to import into based on import wizard choice + auto dbWidget = databaseWidgetFromIndex(i); + if (!dbWidget->isLocked() && dbWidget->database()->uuid() == importInto.first) { + auto group = dbWidget->database()->rootGroup()->findGroupByUuid(importInto.second); + if (group) { + // Extract the root group from the import database + auto importGroup = db->setRootGroup(new Group()); + importGroup->setParent(group); + setCurrentIndex(i); + return; + } } } + break; + case ImportWizard::TEMPORARY_DATABASE: { + // Use the already created database as temporary database + auto dbWidget = new DatabaseWidget(db, this); + addDatabaseTab(dbWidget); + return; } - } + default: + // Start the new database wizard with the imported database + auto newDb = execNewDatabaseWizard(); + if (newDb) { + // Merge the imported db into the new one + Merger merger(db.data(), newDb.data()); + merger.setSkipDatabaseCustomData(true); + merger.merge(); + // Transfer the root group data + newDb->rootGroup()->setName(db->rootGroup()->name()); + newDb->rootGroup()->setNotes(db->rootGroup()->notes()); + // Show the new database + auto dbWidget = new DatabaseWidget(newDb, this); + addDatabaseTab(dbWidget); + newDb->markAsModified(); + return; + } + } + }); - return nullptr; + // use `open` instead of `exec`. `exec` should not be used, see https://doc.qt.io/qt-6/qdialog.html#exec + m_importWizard->show(); } void DatabaseTabWidget::mergeDatabase() @@ -325,7 +343,7 @@ void DatabaseTabWidget::mergeDatabase(const QString& filePath) * Attempt to close the current database and remove its tab afterwards. * * @param index index of the database tab to close - * @return true if database was closed successully + * @return true if database was closed successfully */ bool DatabaseTabWidget::closeCurrentDatabaseTab() { @@ -336,7 +354,7 @@ bool DatabaseTabWidget::closeCurrentDatabaseTab() * Attempt to close the database tab that sent the close request. * * @param index index of the database tab to close - * @return true if database was closed successully + * @return true if database was closed successfully */ bool DatabaseTabWidget::closeDatabaseTabFromSender() { @@ -347,7 +365,7 @@ bool DatabaseTabWidget::closeDatabaseTabFromSender() * Attempt to close a database and remove its tab afterwards. * * @param index index of the database tab to close - * @return true if database was closed successully + * @return true if database was closed successfully */ bool DatabaseTabWidget::closeDatabaseTab(int index) { @@ -358,7 +376,7 @@ bool DatabaseTabWidget::closeDatabaseTab(int index) * Attempt to close a database and remove its tab afterwards. * * @param dbWidget \link DatabaseWidget to close - * @return true if database was closed successully + * @return true if database was closed successfully */ bool DatabaseTabWidget::closeDatabaseTab(DatabaseWidget* dbWidget) { @@ -418,7 +436,7 @@ bool DatabaseTabWidget::saveDatabaseAs(int index) auto* dbWidget = databaseWidgetFromIndex(index); bool ok = dbWidget->saveAs(); if (ok) { - updateLastDatabases(dbWidget->database()->filePath()); + updateLastDatabases(dbWidget->database()); } return ok; } @@ -432,7 +450,7 @@ bool DatabaseTabWidget::saveDatabaseBackup(int index) auto* dbWidget = databaseWidgetFromIndex(index); bool ok = dbWidget->saveBackup(); if (ok) { - updateLastDatabases(dbWidget->database()->filePath()); + updateLastDatabases(dbWidget->database()); } return ok; } @@ -535,21 +553,29 @@ bool DatabaseTabWidget::warnOnExport() return ans == MessageBox::Yes; } +void DatabaseTabWidget::showDatabaseReports(bool state) +{ + if (state) { + currentDatabaseWidget()->switchToDatabaseReports(); + } else { + currentDatabaseWidget()->switchToMainView(); + } +} + +void DatabaseTabWidget::showDatabaseSettings(bool state) +{ + if (state) { + currentDatabaseWidget()->switchToDatabaseSettings(); + } else { + currentDatabaseWidget()->switchToMainView(); + } +} + void DatabaseTabWidget::showDatabaseSecurity() { currentDatabaseWidget()->switchToDatabaseSecurity(); } -void DatabaseTabWidget::showDatabaseReports() -{ - currentDatabaseWidget()->switchToDatabaseReports(); -} - -void DatabaseTabWidget::showDatabaseSettings() -{ - currentDatabaseWidget()->switchToDatabaseSettings(); -} - #ifdef WITH_XC_BROWSER_PASSKEYS void DatabaseTabWidget::showPasskeys() { @@ -565,6 +591,11 @@ void DatabaseTabWidget::importPasskeyToEntry() { currentDatabaseWidget()->showImportPasskeyDialog(true); } + +void DatabaseTabWidget::removePasskeyFromEntry() +{ + currentDatabaseWidget()->removePasskeyFromEntry(); +} #endif bool DatabaseTabWidget::isModified(int index) const @@ -616,6 +647,11 @@ QString DatabaseTabWidget::tabName(int index) tabName = tr("%1 [Locked]", "Database tab name modifier").arg(tabName); } + if (dbWidget->database()->isTemporaryDatabase()) { + tabName = tr("%1 [Temporary]", "Database tab name modifier").arg(tabName); + } + + // needs to be last check, as MainWindow may remove the asterisk again if (dbWidget->database()->isModified()) { tabName.append("*"); } @@ -640,6 +676,12 @@ void DatabaseTabWidget::updateTabName(int index) index = indexOf(dbWidget); setTabText(index, tabName(index)); setTabToolTip(index, dbWidget->displayFilePath()); + auto iconIndex = dbWidget->database()->publicIcon(); + if (iconIndex >= 0 && iconIndex < databaseIcons()->count()) { + setTabIcon(index, databaseIcons()->icon(iconIndex)); + } else { + setTabIcon(index, {}); + } emit tabNameChanged(); } @@ -688,6 +730,13 @@ void DatabaseTabWidget::lockDatabasesDelayed() } } +void DatabaseTabWidget::lockDatabasesOnUserSwitch() +{ + if (config()->get(Config::Security_LockDatabaseOnUserSwitch).toBool()) { + lockDatabases(); + } +} + /** * Unlock a database with an unlock popup dialog. * @@ -739,6 +788,11 @@ void DatabaseTabWidget::unlockAnyDatabaseInDialog(DatabaseOpenDialog::Intent int displayUnlockDialog(); } +void DatabaseTabWidget::unlockDatabaseInDialogForSync(const QString& filePath) +{ + unlockDatabaseInDialog(currentDatabaseWidget(), DatabaseOpenDialog::Intent::RemoteSync, filePath); +} + /** * Display the unlock dialog after it's been initialized. * This is an internal method, it should only be called by unlockDatabaseInDialog or unlockAnyDatabaseInDialog. @@ -765,7 +819,7 @@ void DatabaseTabWidget::handleDatabaseUnlockDialogFinished(bool accepted, Databa { // change the active tab to the database that was just unlocked in the dialog auto intent = m_databaseOpenDialog->intent(); - if (accepted && intent != DatabaseOpenDialog::Intent::Merge) { + if (accepted && intent != DatabaseOpenDialog::Intent::Merge && intent != DatabaseOpenDialog::Intent::RemoteSync) { int index = indexOf(dbWidget); if (index != -1) { setCurrentIndex(index); @@ -777,6 +831,9 @@ void DatabaseTabWidget::handleDatabaseUnlockDialogFinished(bool accepted, Databa m_dbWidgetPendingLock = dbWidget; } + // If browser extension requested the unlock make sure cancel is handled + m_databaseOpenInProgress = false; + // signal other objects that the dialog finished emit databaseUnlockDialogFinished(accepted, dbWidget); } @@ -800,8 +857,12 @@ void DatabaseTabWidget::relockPendingDatabase() m_dbWidgetPendingLock = nullptr; } -void DatabaseTabWidget::updateLastDatabases(const QString& filename) +void DatabaseTabWidget::updateLastDatabases(const QSharedPointer& database) { + if (database->isTemporaryDatabase() || database->filePath().isEmpty()) { + return; + } + auto filename = database->filePath(); if (!config()->get(Config::RememberLastDatabases).toBool()) { config()->remove(Config::LastDatabases); } else { @@ -821,10 +882,7 @@ void DatabaseTabWidget::updateLastDatabases() auto dbWidget = currentDatabaseWidget(); if (dbWidget) { - auto filePath = dbWidget->database()->filePath(); - if (!filePath.isEmpty()) { - updateLastDatabases(filePath); - } + updateLastDatabases(dbWidget->database()); } } diff --git a/src/gui/DatabaseTabWidget.h b/src/gui/DatabaseTabWidget.h index 5c995b536..a5074a84c 100644 --- a/src/gui/DatabaseTabWidget.h +++ b/src/gui/DatabaseTabWidget.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2023 KeePassXC Team + * Copyright (C) 2024 KeePassXC Team * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -21,6 +21,7 @@ #include "DatabaseOpenDialog.h" #include "config-keepassx.h" #include "gui/MessageWidget.h" +#include "wizard/ImportWizard.h" #include #include @@ -64,7 +65,7 @@ public slots: DatabaseWidget* newDatabase(); void openDatabase(); void mergeDatabase(); - DatabaseWidget* importFile(); + void importFile(); bool saveDatabase(int index = -1); bool saveDatabaseAs(int index = -1); bool saveDatabaseBackup(int index = -1); @@ -74,19 +75,22 @@ public slots: bool lockDatabases(); void lockDatabasesDelayed(); + void lockDatabasesOnUserSwitch(); void closeDatabaseFromSender(); void unlockDatabaseInDialog(DatabaseWidget* dbWidget, DatabaseOpenDialog::Intent intent); void unlockDatabaseInDialog(DatabaseWidget* dbWidget, DatabaseOpenDialog::Intent intent, const QString& filePath); + void unlockDatabaseInDialogForSync(const QString& filePath); void unlockAnyDatabaseInDialog(DatabaseOpenDialog::Intent intent); void relockPendingDatabase(); + void showDatabaseReports(bool state); + void showDatabaseSettings(bool state); void showDatabaseSecurity(); - void showDatabaseReports(); - void showDatabaseSettings(); #ifdef WITH_XC_BROWSER_PASSKEYS void showPasskeys(); void importPasskey(); void importPasskeyToEntry(); + void removePasskeyFromEntry(); #endif void performGlobalAutoType(const QString& search); void performBrowserUnlock(); @@ -113,13 +117,14 @@ private slots: private: QSharedPointer execNewDatabaseWizard(); - void updateLastDatabases(const QString& filename); + void updateLastDatabases(const QSharedPointer& database); bool warnOnExport(); void displayUnlockDialog(); QPointer m_dbWidgetStateSync; QPointer m_dbWidgetPendingLock; QPointer m_databaseOpenDialog; + QPointer m_importWizard; QTimer m_lockDelayTimer; bool m_databaseOpenInProgress; }; diff --git a/src/gui/DatabaseWidget.cpp b/src/gui/DatabaseWidget.cpp index 04c9e337b..a9f7f5a81 100644 --- a/src/gui/DatabaseWidget.cpp +++ b/src/gui/DatabaseWidget.cpp @@ -32,6 +32,7 @@ #include #include "autotype/AutoType.h" +#include "core/AsyncTask.h" #include "core/EntrySearcher.h" #include "core/Merger.h" #include "core/Tools.h" @@ -55,6 +56,8 @@ #include "gui/tag/TagView.h" #include "gui/widgets/ElidedLabel.h" #include "keeshare/KeeShare.h" +#include "remote/RemoteHandler.h" +#include "remote/RemoteSettings.h" #ifdef WITH_XC_NETWORKING #include "gui/IconDownloaderDialog.h" @@ -88,10 +91,16 @@ DatabaseWidget::DatabaseWidget(QSharedPointer db, QWidget* parent) , m_groupView(new GroupView(m_db.data(), this)) , m_tagView(new TagView(this)) , m_saveAttempts(0) + , m_remoteSettings(new RemoteSettings(m_db, this)) , m_entrySearcher(new EntrySearcher(false)) { Q_ASSERT(m_db); + // Read public headers if the database hasn't been opened yet + if (!m_db->isInitialized()) { + m_db->open(nullptr); + } + m_messageWidget->setHidden(true); auto mainLayout = new QVBoxLayout(); @@ -121,8 +130,11 @@ DatabaseWidget::DatabaseWidget(QSharedPointer db, QWidget* parent) m_groupSplitter->setChildrenCollapsible(true); m_groupSplitter->addWidget(m_groupView); m_groupSplitter->addWidget(tagsWidget); - m_groupSplitter->setStretchFactor(0, 70); - m_groupSplitter->setStretchFactor(1, 30); + m_groupSplitter->setStretchFactor(0, 100); + m_groupSplitter->setStretchFactor(1, 0); + m_groupSplitter->setSizes({1, 1}); + // Initial visibility based on config value + m_groupSplitter->setVisible(!config()->get(Config::GUI_HideGroupPanel).toBool()); auto rightHandSideWidget = new QWidget(m_mainSplitter); auto rightHandSideVBox = new QVBoxLayout(); @@ -135,11 +147,12 @@ DatabaseWidget::DatabaseWidget(QSharedPointer db, QWidget* parent) rightHandSideWidget->setLayout(rightHandSideVBox); m_entryView = new EntryView(rightHandSideWidget); - m_mainSplitter->setChildrenCollapsible(true); + m_mainSplitter->setChildrenCollapsible(false); m_mainSplitter->addWidget(m_groupSplitter); m_mainSplitter->addWidget(rightHandSideWidget); - m_mainSplitter->setStretchFactor(0, 30); - m_mainSplitter->setStretchFactor(1, 70); + m_mainSplitter->setStretchFactor(0, 0); + m_mainSplitter->setStretchFactor(1, 100); + m_mainSplitter->setSizes({1, 1}); m_previewSplitter->setOrientation(Qt::Vertical); m_previewSplitter->setChildrenCollapsible(true); @@ -175,6 +188,7 @@ DatabaseWidget::DatabaseWidget(QSharedPointer db, QWidget* parent) m_previewSplitter->setSizes({1, 1}); m_editEntryWidget->setObjectName("editEntryWidget"); + m_historyEditEntryWidget->setObjectName("editEntryHistoryWidget"); m_editGroupWidget->setObjectName("editGroupWidget"); m_reportsDialog->setObjectName("reportsDialog"); m_databaseSettingDialog->setObjectName("databaseSettingsDialog"); @@ -194,6 +208,7 @@ DatabaseWidget::DatabaseWidget(QSharedPointer db, QWidget* parent) connect(m_previewSplitter, SIGNAL(splitterMoved(int,int)), SIGNAL(splitterSizesChanged())); connect(this, SIGNAL(currentModeChanged(DatabaseWidget::Mode)), m_previewView, SLOT(setDatabaseMode(DatabaseWidget::Mode))); connect(m_previewView, SIGNAL(entryUrlActivated(Entry*)), SLOT(openUrlForEntry(Entry*))); + connect(m_previewView, SIGNAL(copyTextRequested(const QString&)), SLOT(setClipboardTextAndMinimize(const QString&))); connect(m_entryView, SIGNAL(viewStateChanged()), SIGNAL(entryViewStateChanged())); connect(m_groupView, SIGNAL(groupSelectionChanged()), SLOT(onGroupChanged())); connect(m_groupView, &GroupView::groupFocused, this, [this] { m_previewView->setGroup(currentGroup()); }); @@ -209,11 +224,13 @@ DatabaseWidget::DatabaseWidget(QSharedPointer db, QWidget* parent) connect(m_databaseOpenWidget, SIGNAL(dialogFinished(bool)), SLOT(loadDatabase(bool))); connect(this, SIGNAL(currentChanged(int)), SLOT(emitCurrentModeChanged())); connect(this, SIGNAL(requestGlobalAutoType(const QString&)), parent, SLOT(performGlobalAutoType(const QString&))); + connect(config(), &Config::changed, this, &DatabaseWidget::onConfigChanged); // clang-format on connectDatabaseSignals(); m_blockAutoSave = false; + m_reloading = false; m_autosaveTimer = new QTimer(this); m_autosaveTimer->setSingleShot(true); @@ -257,15 +274,26 @@ QSharedPointer DatabaseWidget::database() const DatabaseWidget::Mode DatabaseWidget::currentMode() const { - if (currentWidget() == nullptr) { - return Mode::None; - } else if (currentWidget() == m_mainWidget) { - return Mode::ViewMode; - } else if (currentWidget() == m_databaseOpenWidget) { - return Mode::LockedMode; + auto mode = Mode::None; + auto widget = currentWidget(); + if (widget == m_mainWidget) { + mode = Mode::ViewMode; + } else if (widget == m_databaseOpenWidget) { + mode = Mode::LockedMode; + } else if (widget == m_reportsDialog) { + mode = Mode::ReportsMode; + } else if (widget == m_databaseSettingDialog) { + mode = Mode::DatabaseSettingsMode; + } else if (widget == m_editEntryWidget || widget == m_historyEditEntryWidget) { + mode = Mode::EditEntryMode; + } else if (widget == m_editGroupWidget) { + mode = Mode::EditGroupMode; } else { - return Mode::EditMode; + // We are missing a condition if we reach here + Q_ASSERT(false); } + + return mode; } bool DatabaseWidget::isLocked() const @@ -361,20 +389,27 @@ QHash> DatabaseWidget::splitterSizes() const void DatabaseWidget::setSplitterSizes(const QHash>& sizes) { + // Set the splitter sizes, if the size is invalid set a default ratio based on this widget size for (auto itr = sizes.constBegin(); itr != sizes.constEnd(); ++itr) { - // Less than two sizes indicates an invalid value - if (itr.value().size() < 2) { - continue; - } + auto value = itr.value(); switch (itr.key()) { case Config::GUI_SplitterState: - m_mainSplitter->setSizes(itr.value()); + if (value.size() < 2) { + value = QList({static_cast(width() * 0.25), static_cast(width() * 0.75)}); + } + m_mainSplitter->setSizes(value); break; case Config::GUI_PreviewSplitterState: - m_previewSplitter->setSizes(itr.value()); + if (value.size() < 2) { + value = QList({static_cast(height() * 0.8), static_cast(height() * 0.2)}); + } + m_previewSplitter->setSizes(value); break; case Config::GUI_GroupSplitterState: - m_groupSplitter->setSizes(itr.value()); + if (value.size() < 2) { + value = QList({static_cast(height() * 0.6), static_cast(height() * 0.4)}); + } + m_groupSplitter->setSizes(value); break; default: break; @@ -382,6 +417,15 @@ void DatabaseWidget::setSplitterSizes(const QHash> } } +void DatabaseWidget::onConfigChanged(Config::ConfigKey key) +{ + if (key == Config::GUI_HideGroupPanel) { + // Toggle the group splitter visibility and reset the size + m_groupSplitter->setVisible(!config()->get(Config::GUI_HideGroupPanel).toBool()); + setSplitterSizes({{Config::GUI_SplitterState, QList({})}}); + } +} + void DatabaseWidget::setSearchStringForAutoType(const QString& search) { m_searchStringForAutoType = search; @@ -450,6 +494,7 @@ void DatabaseWidget::replaceDatabase(QSharedPointer db) connectDatabaseSignals(); m_groupView->changeDatabase(m_db); m_tagView->setDatabase(m_db); + m_remoteSettings->setDatabase(m_db); // Restore the new parent group pointer, if not found default to the root group // this prevents data loss when merging a database while creating a new entry @@ -530,6 +575,17 @@ void DatabaseWidget::setupTotp() setupTotpDialog->open(); } +void DatabaseWidget::expireSelectedEntries() +{ + const QModelIndexList selected = m_entryView->selectionModel()->selectedRows(); + for (const auto& index : selected) { + auto entry = m_entryView->entryFromIndex(index); + if (entry) { + entry->expireNow(); + } + } +} + void DatabaseWidget::deleteSelectedEntries() { const QModelIndexList selected = m_entryView->selectionModel()->selectedRows(); @@ -658,29 +714,6 @@ void DatabaseWidget::copyUsername() void DatabaseWidget::copyPassword() { - // Some platforms do not properly trap Ctrl+C copy shortcut - // if a text edit or label has focus pass the copy operation to it - - bool clearClipboard = config()->get(Config::Security_ClearClipboard).toBool(); - - auto plainTextEdit = qobject_cast(focusWidget()); - if (plainTextEdit && plainTextEdit->textCursor().hasSelection()) { - clipboard()->setText(plainTextEdit->textCursor().selectedText(), clearClipboard); - return; - } - - auto label = qobject_cast(focusWidget()); - if (label && label->hasSelectedText()) { - clipboard()->setText(label->selectedText(), clearClipboard); - return; - } - - auto textEdit = qobject_cast(focusWidget()); - if (textEdit && textEdit->textCursor().hasSelection()) { - clipboard()->setText(textEdit->textCursor().selection().toPlainText(), clearClipboard); - return; - } - auto currentEntry = currentSelectedEntry(); if (currentEntry) { setClipboardTextAndMinimize(currentEntry->resolveMultiplePlaceholders(currentEntry->password())); @@ -721,6 +754,34 @@ void DatabaseWidget::copyAttribute(QAction* action) } } +bool DatabaseWidget::copyFocusedTextSelection() +{ + // If a focused child widget has text selected, copy that text to the clipboard + // and return true. Otherwise, return false. + + const bool clearClipboard = config()->get(Config::Security_ClearClipboard).toBool(); + + const auto plainTextEdit = qobject_cast(focusWidget()); + if (plainTextEdit && plainTextEdit->textCursor().hasSelection()) { + clipboard()->setText(plainTextEdit->textCursor().selectedText(), clearClipboard); + return true; + } + + const auto label = qobject_cast(focusWidget()); + if (label && label->hasSelectedText()) { + clipboard()->setText(label->selectedText(), clearClipboard); + return true; + } + + const auto textEdit = qobject_cast(focusWidget()); + if (textEdit && textEdit->textCursor().hasSelection()) { + clipboard()->setText(textEdit->textCursor().selection().toPlainText(), clearClipboard); + return true; + } + + return false; +} + void DatabaseWidget::filterByTag() { QStringList searchTerms; @@ -942,7 +1003,7 @@ void DatabaseWidget::openUrlForEntry(Entry* entry) this); msgbox.setDefaultButton(QMessageBox::No); - QCheckBox* checkbox = new QCheckBox(tr("Remember my choice"), &msgbox); + auto checkbox = new QCheckBox(tr("Remember my choice"), &msgbox); msgbox.setCheckBox(checkbox); bool remember = false; QObject::connect(checkbox, &QCheckBox::stateChanged, [&](int state) { @@ -960,7 +1021,16 @@ void DatabaseWidget::openUrlForEntry(Entry* entry) } if (launch) { - QProcess::startDetached(cmdString.mid(6)); + const QString cmd = cmdString.mid(6); +#if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0) + QStringList cmdList = QProcess::splitCommand(cmd); + if (!cmdList.isEmpty()) { + const QString program = cmdList.takeFirst(); + QProcess::startDetached(program, cmdList); + } +#else + QProcess::startDetached(cmd); +#endif if (config()->get(Config::MinimizeOnOpenUrl).toBool()) { getMainWindow()->minimizeOrHide(); @@ -984,7 +1054,7 @@ void DatabaseWidget::openUrlForEntry(Entry* entry) } } -Entry* DatabaseWidget::currentSelectedEntry() +Entry* DatabaseWidget::currentSelectedEntry() const { if (currentWidget() == m_editEntryWidget) { return m_editEntryWidget->currentEntry(); @@ -1064,6 +1134,87 @@ int DatabaseWidget::addChildWidget(QWidget* w) return index; } +void DatabaseWidget::syncWithRemote(const RemoteParams* params) +{ + setDisabled(true); + emit databaseSyncInProgress(); + + QScopedPointer remoteHandler(new RemoteHandler(this)); + RemoteHandler::RemoteResult result; + result.success = false; + result.errorMessage = tr("Remote Sync did not contain any download or upload commands."); + + // Download the database + if (!params->downloadCommand.isEmpty()) { + emit updateSyncProgress(25, tr("Downloading...")); + // Start a download first then merge and upload in the callback + result = remoteHandler->download(params); + if (result.success) { + QString error; + QSharedPointer remoteDb = QSharedPointer::create(); + if (!remoteDb->open(result.filePath, m_db->key(), &error)) { + // Failed to open downloaded remote database with same key + // Unlock downloaded remote database via dialog + syncDatabaseWithLockedDatabase(result.filePath, params); + return; + } + remoteDb->markAsTemporaryDatabase(); + if (!syncWithDatabase(remoteDb, error)) { + // Something failed during the sync process + result.success = false; + result.errorMessage = error; + } + } + } + + uploadAndFinishSync(params, result); +} + +void DatabaseWidget::syncDatabaseWithLockedDatabase(const QString& filePath, const RemoteParams* params) +{ + // disconnect any previously added slots to these signal + disconnect(this, &DatabaseWidget::databaseSyncUnlocked, nullptr, nullptr); + disconnect(this, &DatabaseWidget::databaseSyncUnlockFailed, nullptr, nullptr); + + connect(this, &DatabaseWidget::databaseSyncUnlocked, [this, params](const RemoteHandler::RemoteResult& result) { + uploadAndFinishSync(params, result); + }); + connect(this, &DatabaseWidget::databaseSyncUnlockFailed, [this, params](const RemoteHandler::RemoteResult& result) { + finishSync(params, result); + }); + + emit unlockDatabaseInDialogForSync(filePath); +} + +void DatabaseWidget::uploadAndFinishSync(const RemoteParams* params, RemoteHandler::RemoteResult result) +{ + QScopedPointer remoteHandler(new RemoteHandler(this)); + if (result.success && !params->uploadCommand.isEmpty()) { + emit updateSyncProgress(75, tr("Uploading...")); + result = remoteHandler->upload(result.filePath, params); + } + + finishSync(params, result); +} + +void DatabaseWidget::finishSync(const RemoteParams* params, RemoteHandler::RemoteResult result) +{ + setDisabled(false); + emit updateSyncProgress(-1, ""); + if (result.success) { + emit databaseSyncCompleted(params->name); + showMessage(tr("Remote sync '%1' completed successfully!").arg(params->name), MessageWidget::Positive, false); + } else { + emit databaseSyncFailed(params->name, result.errorMessage); + showErrorMessage(tr("Remote sync '%1' failed: %2").arg(params->name, result.errorMessage)); + } +} + +QList DatabaseWidget::getRemoteParams() const +{ + return m_remoteSettings->getAllRemoteParams(); +} + void DatabaseWidget::switchToMainView(bool previousDialogAccepted) { setCurrentWidget(m_mainWidget); @@ -1162,6 +1313,7 @@ void DatabaseWidget::loadDatabase(bool accepted) } if (accepted) { + emit databaseAboutToUnlock(); replaceDatabase(openWidget->database()); switchToMainView(); processAutoOpen(); @@ -1233,6 +1385,59 @@ void DatabaseWidget::mergeDatabase(bool accepted) emit databaseMerged(m_db); } +void DatabaseWidget::syncUnlockedDatabase(bool accepted) +{ + if (accepted) { + if (!m_db) { + showMessage(tr("No current database."), MessageWidget::Error); + return; + } + + auto* senderDialog = qobject_cast(sender()); + + Q_ASSERT(senderDialog); + if (!senderDialog) { + return; + } + auto destinationDb = senderDialog->database(); + + if (!destinationDb) { + showMessage(tr("No source database, nothing to do."), MessageWidget::Error); + return; + } + + RemoteHandler::RemoteResult result; + QString error; + result.success = syncWithDatabase(destinationDb, error); + result.errorMessage = error; + result.filePath = destinationDb->filePath(); + + emit databaseSyncUnlocked(result); + } + switchToMainView(); +} + +bool DatabaseWidget::syncWithDatabase(const QSharedPointer& otherDb, QString& error) +{ + emit updateSyncProgress(50, tr("Syncing...")); + Merger firstMerge(m_db.data(), otherDb.data()); + Merger secondMerge(otherDb.data(), m_db.data()); + QStringList changeList = firstMerge.merge() + secondMerge.merge(); + + if (!changeList.isEmpty()) { + // Save synced databases + if (!save()) { + error = tr("Error while saving database %1: %2").arg(m_db->filePath(), error); + return false; + } + if (!otherDb->save(Database::Atomic, {}, &error)) { + error = tr("Error while saving database %1: %2").arg(otherDb->filePath(), error); + return false; + } + } + return true; +} + /** * Unlock the database. * @@ -1246,14 +1451,26 @@ void DatabaseWidget::unlockDatabase(bool accepted) if (!senderDialog && (!m_db || !m_db->isInitialized())) { emit closeRequest(); } + if (senderDialog && senderDialog->intent() == DatabaseOpenDialog::Intent::RemoteSync) { + RemoteHandler::RemoteResult result; + result.success = false; + result.errorMessage = "Remote database unlock cancelled."; + emit databaseSyncUnlockFailed(result); + } return; } - if (senderDialog && senderDialog->intent() == DatabaseOpenDialog::Intent::Merge) { - mergeDatabase(accepted); - return; + if (senderDialog) { + if (senderDialog->intent() == DatabaseOpenDialog::Intent::Merge) { + mergeDatabase(accepted); + return; + } else if (senderDialog->intent() == DatabaseOpenDialog::Intent::RemoteSync) { + syncUnlockedDatabase(accepted); + return; + } } + emit databaseAboutToUnlock(); QSharedPointer db; if (senderDialog) { db = senderDialog->database(); @@ -1309,13 +1526,8 @@ void DatabaseWidget::entryActivationSignalReceived(Entry* entry, EntryModel::Mod switchToEntryEdit(entry); } break; - case EntryModel::Url: - if (!entry->url().isEmpty()) { - openUrlForEntry(entry); - } - break; case EntryModel::Totp: - if (entry->hasTotp()) { + if (entry->hasValidTotp()) { setClipboardTextAndMinimize(entry->totp()); } else { setupTotp(); @@ -1334,6 +1546,13 @@ void DatabaseWidget::entryActivationSignalReceived(Entry* entry, EntryModel::Mod // TODO: switch to 'Attachments' tab in details view/pane // case EntryModel::Attachments: // break; + case EntryModel::Url: + if (!entry->url().isEmpty() && config()->get(Config::OpenURLOnDoubleClick).toBool()) { + openUrlForEntry(entry); + break; + } + // Note, order matters here. We want to fall into the default case. + [[fallthrough]]; default: switchToEntryEdit(entry); } @@ -1341,14 +1560,18 @@ void DatabaseWidget::entryActivationSignalReceived(Entry* entry, EntryModel::Mod void DatabaseWidget::switchToDatabaseReports() { - m_reportsDialog->load(m_db); - setCurrentWidget(m_reportsDialog); + if (currentMode() != Mode::ReportsMode) { + m_reportsDialog->load(m_db); + setCurrentWidget(m_reportsDialog); + } } void DatabaseWidget::switchToDatabaseSettings() { - m_databaseSettingDialog->load(m_db); - setCurrentWidget(m_databaseSettingDialog); + if (currentMode() != Mode::DatabaseSettingsMode) { + m_databaseSettingDialog->load(m_db); + setCurrentWidget(m_databaseSettingDialog); + } } void DatabaseWidget::switchToOpenDatabase() @@ -1406,6 +1629,12 @@ void DatabaseWidget::switchToDatabaseSecurity() m_databaseSettingDialog->showDatabaseKeySettings(); } +void DatabaseWidget::switchToRemoteSettings() +{ + switchToDatabaseSettings(); + m_databaseSettingDialog->showRemoteSettings(); +} + #ifdef WITH_XC_BROWSER_PASSKEYS void DatabaseWidget::switchToPasskeys() { @@ -1428,6 +1657,22 @@ void DatabaseWidget::showImportPasskeyDialog(bool isEntry) passkeyImporter.importPasskey(m_db); } } + +void DatabaseWidget::removePasskeyFromEntry() +{ + auto currentEntry = currentSelectedEntry(); + if (!currentEntry) { + return; + } + + auto result = MessageBox::question(this, + tr("Remove passkey from entry"), + tr("Do you want to remove the passkey from this entry?"), + MessageBox::Remove | MessageBox::Cancel); + if (result == MessageBox::Remove) { + currentEntry->removePasskey(); + } +} #endif void DatabaseWidget::performUnlockDatabase(const QString& password, const QString& keyfile) @@ -1570,6 +1815,7 @@ void DatabaseWidget::onGroupChanged() void DatabaseWidget::onDatabaseModified() { refreshSearch(); + m_remoteSettings->loadSettings(); int autosaveDelayMs = m_db->metadata()->autosaveDelayMin() * 60 * 1000; // min to msec for QTimer bool autosaveAfterEveryChangeConfig = config()->get(Config::AutoSaveAfterEveryChange).toBool(); if (autosaveDelayMs > 0 && autosaveAfterEveryChangeConfig) { @@ -1667,16 +1913,13 @@ void DatabaseWidget::onEntryChanged(Entry* entry) bool DatabaseWidget::canCloneCurrentGroup() const { - bool isRootGroup = m_db->rootGroup() == m_groupView->currentGroup(); - // bool isRecycleBin = isRecycleBinSelected(); - - return !isRootGroup; + auto currentGroup = m_groupView->currentGroup(); + return currentGroup != m_db->rootGroup() && currentGroup != m_db->metadata()->recycleBin(); } bool DatabaseWidget::canDeleteCurrentGroup() const { - bool isRootGroup = m_db->rootGroup() == m_groupView->currentGroup(); - return !isRootGroup; + return currentGroup() != m_db->rootGroup(); } Group* DatabaseWidget::currentGroup() const @@ -1743,8 +1986,13 @@ bool DatabaseWidget::focusNextPrevChild(bool next) bool DatabaseWidget::lock() { - if (isLocked()) { - return true; + if (isLocked() || m_attemptingLock) { + return isLocked(); + } + + // ignore when reloading + if (m_reloading) { + return false; } // Don't try to lock the database while saving, this will cause a deadlock @@ -1753,6 +2001,8 @@ bool DatabaseWidget::lock() return false; } + m_attemptingLock = true; + emit databaseLockRequested(); // Force close any modal widgets associated with this widget @@ -1777,6 +2027,7 @@ bool DatabaseWidget::lock() MessageBox::Discard | MessageBox::Cancel, MessageBox::Cancel); if (result == MessageBox::Cancel) { + m_attemptingLock = false; return false; } } @@ -1787,6 +2038,18 @@ bool DatabaseWidget::lock() if (config()->get(Config::AutoSaveOnExit).toBool() || config()->get(Config::AutoSaveAfterEveryChange).toBool()) { saved = save(); + + if (!saved) { + // detect if a reload was triggered + bool reloadTriggered = false; + auto connection = + connect(this, &DatabaseWidget::reloadBegin, [&reloadTriggered] { reloadTriggered = true; }); + QApplication::processEvents(); + disconnect(connection); + if (reloadTriggered) { + return false; + } + } } if (!saved) { @@ -1803,9 +2066,11 @@ bool DatabaseWidget::lock() MessageBox::Save); if (result == MessageBox::Save) { if (!save()) { + m_attemptingLock = false; return false; } } else if (result == MessageBox::Cancel) { + m_attemptingLock = false; return false; } } @@ -1835,59 +2100,85 @@ bool DatabaseWidget::lock() switchToOpenDatabase(m_db->filePath()); auto newDb = QSharedPointer::create(m_db->filePath()); + newDb->open(nullptr); replaceDatabase(newDb); + m_attemptingLock = false; emit databaseLocked(); return true; } -void DatabaseWidget::reloadDatabaseFile() +void DatabaseWidget::reloadDatabaseFile(bool triggeredBySave) { - // Ignore reload if we are locked, saving, or currently editing an entry or group - if (!m_db || isLocked() || isEntryEditActive() || isGroupEditActive() || isSaving()) { + if (triggeredBySave) { + // not a failed save attempt due to file locking + m_saveAttempts = 0; + } + // Ignore reload if we are locked, saving, reloading, or currently editing an entry or group + if (!m_db || isLocked() || isEntryEditActive() || isGroupEditActive() || isSaving() || m_reloading) { return; } m_blockAutoSave = true; + m_reloading = true; - if (!config()->get(Config::AutoReloadOnChange).toBool()) { + emit reloadBegin(); + + if (!triggeredBySave && !config()->get(Config::AutoReloadOnChange).toBool()) { // Ask if we want to reload the db - auto result = MessageBox::question(this, - tr("File has changed"), - tr("The database file has changed. Do you want to load the changes?"), - MessageBox::Yes | MessageBox::No); + auto result = MessageBox::question( + this, + tr("File has changed"), + QString("%1.\n%2").arg(tr("The database file \"%1\" was modified externally").arg(displayFileName()), + tr("Do you want to load the changes?")), + MessageBox::Yes | MessageBox::No); if (result == MessageBox::No) { // Notify everyone the database does not match the file m_db->markAsModified(); + m_reloading = false; + + emit reloadEnd(); return; } } + // Remove any latent error messages and switch to progress updates + hideMessage(); + emit updateSyncProgress(0, tr("Reloading database…")); + // Lock out interactions m_entryView->setDisabled(true); m_groupView->setDisabled(true); m_tagView->setDisabled(true); QApplication::processEvents(); - QString error; - auto db = QSharedPointer::create(m_db->filePath()); - if (db->open(database()->key(), &error)) { - if (m_db->isModified() || db->hasNonDataChanges()) { - // Ask if we want to merge changes into new database - auto result = MessageBox::question( - this, - tr("Merge Request"), - tr("The database file has changed and you have unsaved changes.\nDo you want to merge your changes?"), - MessageBox::Merge | MessageBox::Discard, - MessageBox::Merge); + auto reloadFinish = [this](bool hideMsg = true) { + // Return control + m_entryView->setDisabled(false); + m_groupView->setDisabled(false); + m_tagView->setDisabled(false); - if (result == MessageBox::Merge) { - // Merge the old database into the new one - Merger merger(m_db.data(), db.data()); - merger.merge(); - } + m_reloading = false; + + // Keep the previous message visible for 2 seconds if not hiding + QTimer::singleShot(hideMsg ? 0 : 2000, this, [this] { emit updateSyncProgress(-1, ""); }); + + emit reloadEnd(); + }; + auto reloadCanceled = [this, reloadFinish] { + // Mark db as modified since existing data may differ from file or file was deleted + m_db->markAsModified(); + + emit updateSyncProgress(100, tr("Reload canceled")); + reloadFinish(false); + }; + auto reloadContinue = [this, triggeredBySave, reloadFinish](QSharedPointer db, bool merge) { + if (merge) { + // Merge the old database into the new one + Merger merger(m_db.data(), db.data()); + merger.merge(); } QUuid groupBeforeReload = m_db->rootGroup()->uuid(); @@ -1904,17 +2195,108 @@ void DatabaseWidget::reloadDatabaseFile() processAutoOpen(); restoreGroupEntryFocus(groupBeforeReload, entryBeforeReload); m_blockAutoSave = false; - } else { - showMessage(tr("Could not open the new database file while attempting to autoreload.\nError: %1").arg(error), - MessageWidget::Error); - // Mark db as modified since existing data may differ from file or file was deleted - m_db->markAsModified(); + + emit updateSyncProgress(100, tr("Reload successful")); + reloadFinish(false); + + // If triggered by save, attempt another save + if (triggeredBySave) { + save(); + } + }; + + auto db = QSharedPointer::create(m_db->filePath()); + bool openResult = db->open(database()->key()); + + // skip if the db is unchanged, or the db file is gone or for sure not a kp-db + if (bool sameHash = db->fileBlockHash() == m_db->fileBlockHash() || db->fileBlockHash().isEmpty()) { + if (!sameHash) { + // db file gone or invalid so mark modified + m_db->markAsModified(); + } + m_blockAutoSave = false; + reloadFinish(); + return; } - // Return control - m_entryView->setDisabled(false); - m_groupView->setDisabled(false); - m_tagView->setDisabled(false); + bool merge = false; + QString changesActionStr; + if (triggeredBySave || m_db->isModified() || m_db->hasNonDataChanges()) { + emit updateSyncProgress(50, tr("Reload pending user action…")); + + // Ask how to proceed + auto message = tr("The database file \"%1\" was modified externally.
    " + "How would you like to proceed?

    " + "Merge all changes
    " + "Ignore the changes on disk until save
    " + "Discard unsaved changes") + .arg(displayFileName()); + auto buttons = MessageBox::Merge | MessageBox::Discard | MessageBox::Ignore | MessageBox::Cancel; + // Different message if we are attempting to save + if (triggeredBySave) { + message = tr("The database file \"%1\" was modified externally.
    " + "How would you like to proceed?

    " + "Merge all changes then save
    " + "Overwrite the changes on disk
    " + "Discard unsaved changes") + .arg(displayFileName()); + buttons = MessageBox::Merge | MessageBox::Discard | MessageBox::Overwrite | MessageBox::Cancel; + } + + auto result = MessageBox::question(this, tr("Reload database"), message, buttons, MessageBox::Merge); + switch (result) { + case MessageBox::Cancel: + reloadCanceled(); + return; + case MessageBox::Overwrite: + case MessageBox::Ignore: + m_db->setIgnoreFileChangesUntilSaved(true); + m_blockAutoSave = false; + reloadFinish(!triggeredBySave); + // If triggered by save, attempt another save + if (triggeredBySave) { + save(); + emit updateSyncProgress(100, tr("Database file overwritten.")); + } + return; + case MessageBox::Merge: + merge = true; + default: + break; + } + } + + // Database file on disk previously opened successfully + if (openResult) { + reloadContinue(std::move(db), merge); + return; + } + + // The user needs to provide credentials + auto dbWidget = new DatabaseWidget(std::move(db)); + auto openDialog = new DatabaseOpenDialog(this); + connect(openDialog, &QObject::destroyed, [=](QObject*) { dbWidget->deleteLater(); }); + connect(openDialog, &DatabaseOpenDialog::dialogFinished, this, [=](bool accepted, DatabaseWidget*) { + if (accepted) { + reloadContinue(openDialog->database(), merge); + } else { + reloadCanceled(); + } + }); + openDialog->setAttribute(Qt::WA_DeleteOnClose); + openDialog->addDatabaseTab(dbWidget); + openDialog->setActiveDatabaseTab(dbWidget); + openDialog->showMessage(tr("Database file on disk cannot be unlocked with current credentials.
    " + "Enter new credentials and/or present hardware key to continue."), + MessageWidget::Error, + MessageWidget::DisableAutoHide); + + // ensure the main window is visible for this + getMainWindow()->bringToFront(); + // show the unlock dialog + openDialog->show(); + openDialog->raise(); + openDialog->activateWindow(); } int DatabaseWidget::numberOfSelectedEntries() const @@ -1931,7 +2313,7 @@ QStringList DatabaseWidget::customEntryAttributes() const { Entry* entry = m_entryView->currentEntry(); if (!entry) { - return QStringList(); + return {}; } return entry->attributes()->customKeys(); @@ -2004,7 +2386,7 @@ bool DatabaseWidget::currentEntryHasTotp() if (!currentEntry) { return false; } - return currentEntry->hasTotp(); + return currentEntry->hasValidTotp(); } #ifdef WITH_XC_SSHAGENT @@ -2020,6 +2402,14 @@ bool DatabaseWidget::currentEntryHasSshKey() } #endif +#ifdef WITH_XC_BROWSER_PASSKEYS +bool DatabaseWidget::currentEntryHasPasskey() +{ + auto currentEntry = m_entryView->currentEntry(); + return currentEntry && currentEntry->hasPasskey(); +} +#endif + bool DatabaseWidget::currentEntryHasNotes() { auto currentEntry = currentSelectedEntry(); @@ -2069,6 +2459,11 @@ bool DatabaseWidget::save() return true; } + // Do no try to save if the database is being reloaded + if (m_reloading) { + return false; + } + // Read-only and new databases ask for filename if (m_db->filePath().isEmpty()) { return saveAs(); @@ -2083,6 +2478,7 @@ bool DatabaseWidget::save() m_saveAttempts = 0; m_blockAutoSave = false; m_autosaveTimer->stop(); // stop autosave delay to avoid triggering another save + hideMessage(); return true; } @@ -2124,6 +2520,11 @@ bool DatabaseWidget::saveAs() return true; } + // Do no try to save if the database is being reloaded + if (m_reloading) { + return false; + } + QString oldFilePath = m_db->filePath(); if (!QFileInfo::exists(oldFilePath)) { QString defaultFileName = config()->get(Config::DefaultDatabaseFileName).toString(); @@ -2132,7 +2533,7 @@ bool DatabaseWidget::saveAs() + (defaultFileName.isEmpty() ? tr("Passwords").append(".kdbx") : defaultFileName)); } const QString newFilePath = fileDialog()->getSaveFileName( - this, tr("Save database as"), oldFilePath, tr("KeePass 2 Database").append(" (*.kdbx)"), nullptr, nullptr); + this, tr("Save database as"), oldFilePath, tr("KeePass 2 Database").append(" (*.kdbx)")); bool ok = false; if (!newFilePath.isEmpty()) { @@ -2153,9 +2554,10 @@ bool DatabaseWidget::performSave(QString& errorMessage, const QString& fileName) QPointer focusWidget(qApp->focusWidget()); // Lock out interactions - m_entryView->setDisabled(true); - m_groupView->setDisabled(true); - m_tagView->setDisabled(true); + auto mainWindow = getMainWindow(); + if (mainWindow) { + mainWindow->setDisabled(true); + } QApplication::processEvents(); Database::SaveAction saveAction = Database::Atomic; @@ -2195,9 +2597,9 @@ bool DatabaseWidget::performSave(QString& errorMessage, const QString& fileName) } // Return control - m_entryView->setDisabled(false); - m_groupView->setDisabled(false); - m_tagView->setDisabled(false); + if (mainWindow) { + mainWindow->setDisabled(false); + } if (focusWidget && focusWidget->isVisible()) { focusWidget->setFocus(); @@ -2213,47 +2615,45 @@ bool DatabaseWidget::performSave(QString& errorMessage, const QString& fileName) */ bool DatabaseWidget::saveBackup() { - while (true) { - QString oldFilePath = m_db->filePath(); - if (!QFileInfo::exists(oldFilePath)) { - QString defaultFileName = config()->get(Config::DefaultDatabaseFileName).toString(); - oldFilePath = QDir::toNativeSeparators( - FileDialog::getLastDir("db") + "/" - + (defaultFileName.isEmpty() ? tr("Passwords").append(".kdbx") : defaultFileName)); - } + QString oldFilePath = m_db->filePath(); + if (!QFileInfo::exists(oldFilePath)) { + QString defaultFileName = config()->get(Config::DefaultDatabaseFileName).toString(); + oldFilePath = + QDir::toNativeSeparators(FileDialog::getLastDir("db") + "/" + + (defaultFileName.isEmpty() ? tr("Passwords").append(".kdbx") : defaultFileName)); + } - const QString newFilePath = fileDialog()->getSaveFileName(this, - tr("Save database backup"), - FileDialog::getLastDir("backup", oldFilePath), - tr("KeePass 2 Database").append(" (*.kdbx)"), - nullptr, - nullptr); + const QString newFilePath = fileDialog()->getSaveFileName(this, + tr("Save database backup"), + FileDialog::getLastDir("backup", oldFilePath), + tr("KeePass 2 Database").append(" (*.kdbx)")); - if (!newFilePath.isEmpty()) { - // Ensure we don't recurse back into this function - m_db->setFilePath(newFilePath); - m_saveAttempts = 0; - - bool modified = m_db->isModified(); - - if (!save()) { - // Failed to save, try again - m_db->setFilePath(oldFilePath); - continue; - } - - m_db->setFilePath(oldFilePath); - if (modified) { - // Source database is marked as clean when copy is saved, even if source has unsaved changes - m_db->markAsModified(); - } - FileDialog::saveLastDir("backup", newFilePath, true); - return true; - } - - // Canceled file selection + // Early out if we canceled the file selection + if (newFilePath.isEmpty()) { return false; } + + // Record modified state so we can restore after save + bool modified = m_db->isModified(); + + QString error; + bool ok = m_db->saveAs(newFilePath, Database::DirectWrite, {}, &error); + + // Restore database to original state + m_db->setFilePath(oldFilePath); + if (modified) { + // Source database is marked as clean when copy is saved, even if source has unsaved changes + m_db->markAsModified(); + } + + if (!ok) { + // Failed to save backup, post the error + showErrorMessage(tr("Failed to save backup database: %1").arg(error)); + return false; + } + + FileDialog::saveLastDir("backup", newFilePath, true); + return true; } void DatabaseWidget::showMessage(const QString& text, @@ -2279,7 +2679,9 @@ void DatabaseWidget::hideMessage() bool DatabaseWidget::isRecycleBinSelected() const { - return m_groupView->currentGroup() && m_groupView->currentGroup() == m_db->metadata()->recycleBin(); + auto group = currentGroup(); + auto entry = currentSelectedEntry(); + return (group && group->isRecycled()) || (entry && entry->isRecycled()); } void DatabaseWidget::emptyRecycleBin() diff --git a/src/gui/DatabaseWidget.h b/src/gui/DatabaseWidget.h index 681260009..a96c9d488 100644 --- a/src/gui/DatabaseWidget.h +++ b/src/gui/DatabaseWidget.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2023 KeePassXC Team + * Copyright (C) 2024 KeePassXC Team * Copyright (C) 2010 Felix Geyer * * This program is free software: you can redistribute it and/or modify @@ -19,7 +19,6 @@ #ifndef KEEPASSX_DATABASEWIDGET_H #define KEEPASSX_DATABASEWIDGET_H -#include #include #include "core/Database.h" @@ -27,6 +26,7 @@ #include "core/Metadata.h" #include "gui/MessageWidget.h" #include "gui/entry/EntryModel.h" +#include "remote/RemoteHandler.h" class DatabaseOpenDialog; class DatabaseOpenWidget; @@ -45,6 +45,8 @@ class QLabel; class EntryPreviewWidget; class TagView; class ElidedLabel; +class RemoteSettings; +struct RemoteParams; namespace Ui { @@ -62,8 +64,11 @@ public: { None, ViewMode, - EditMode, - LockedMode + EditEntryMode, + EditGroupMode, + LockedMode, + ReportsMode, + DatabaseSettingsMode }; explicit DatabaseWidget(QSharedPointer db, QWidget* parent = nullptr); @@ -104,7 +109,7 @@ public: QStringList customEntryAttributes() const; bool isEditWidgetModified() const; void clearAllWidgets(); - Entry* currentSelectedEntry(); + Entry* currentSelectedEntry() const; bool currentEntryHasTitle(); bool currentEntryHasUsername(); bool currentEntryHasPassword(); @@ -122,12 +127,17 @@ public: void setSplitterSizes(const QHash>& sizes); void setSearchStringForAutoType(const QString& search); + void syncWithRemote(const RemoteParams* params); + void syncDatabaseWithLockedDatabase(const QString& filePath, const RemoteParams* params); + QList getRemoteParams() const; + signals: // relayed Database signals void databaseFilePathChanged(const QString& oldPath, const QString& newPath); void databaseModified(); void databaseNonDataChanged(); void databaseSaved(); + void databaseAboutToUnlock(); void databaseUnlocked(); void databaseLockRequested(); void databaseLocked(); @@ -142,6 +152,13 @@ signals: void requestOpenDatabase(const QString& filePath, bool inBackground, const QString& password, const QString& keyFile); void databaseMerged(QSharedPointer mergedDb); + void databaseSyncInProgress(); + void databaseSyncCompleted(const QString& syncName); + void databaseSyncFailed(const QString& syncName, const QString& error); + void databaseSyncUnlockFailed(const RemoteHandler::RemoteResult& result); + void databaseSyncUnlocked(const RemoteHandler::RemoteResult& result); + void unlockDatabaseInDialogForSync(const QString& filePath); + void updateSyncProgress(int percentage, QString message); void groupContextMenuRequested(const QPoint& globalPos); void entryContextMenuRequested(const QPoint& globalPos); void listModeAboutToActivate(); @@ -153,6 +170,8 @@ signals: void clearSearch(); void requestGlobalAutoType(const QString& search); void requestSearch(const QString& search); + void reloadBegin(); + void reloadEnd(); public slots: bool lock(); @@ -163,6 +182,7 @@ public slots: void replaceDatabase(QSharedPointer db); void createEntry(); void cloneEntry(); + void expireSelectedEntries(); void deleteSelectedEntries(); void restoreSelectedEntries(); void deleteEntries(QList entries, bool confirm = true); @@ -176,6 +196,7 @@ public slots: void copyURL(); void copyNotes(); void copyAttribute(QAction* action); + bool copyFocusedTextSelection(); void filterByTag(); void setTag(QAction* action); void showTotp(); @@ -193,6 +214,7 @@ public slots: void performAutoTypePassword(); void performAutoTypePasswordEnter(); void performAutoTypeTOTP(); + void setClipboardTextAndMinimize(const QString& text); void openUrl(); void downloadSelectedFavicons(); void downloadAllFavicons(); @@ -209,9 +231,12 @@ public slots: void switchToDatabaseSecurity(); void switchToDatabaseReports(); void switchToDatabaseSettings(); + void switchToRemoteSettings(); #ifdef WITH_XC_BROWSER_PASSKEYS void switchToPasskeys(); void showImportPasskeyDialog(bool isEntry = false); + void removePasskeyFromEntry(); + bool currentEntryHasPasskey(); #endif void switchToOpenDatabase(); void switchToOpenDatabase(const QString& filePath); @@ -258,14 +283,18 @@ private slots: void loadDatabase(bool accepted); void unlockDatabase(bool accepted); void mergeDatabase(bool accepted); + void syncUnlockedDatabase(bool accepted); + bool syncWithDatabase(const QSharedPointer& otherDb, QString& error); + void uploadAndFinishSync(const RemoteParams* params, RemoteHandler::RemoteResult result); + void finishSync(const RemoteParams* params, RemoteHandler::RemoteResult result); void emitCurrentModeChanged(); // Database autoreload slots - void reloadDatabaseFile(); + void reloadDatabaseFile(bool triggeredBySave); void restoreGroupEntryFocus(const QUuid& groupUuid, const QUuid& EntryUuid); + void onConfigChanged(Config::ConfigKey key); private: int addChildWidget(QWidget* w); - void setClipboardTextAndMinimize(const QString& text); void processAutoOpen(); void openDatabaseFromEntry(const Entry* entry, bool inBackground = true); void performIconDownloads(const QList& entries, bool force = false, bool downloadInBackground = false); @@ -299,6 +328,9 @@ private: QUuid m_entryBeforeLock; int m_saveAttempts; + bool m_attemptingLock = false; + + QScopedPointer m_remoteSettings; // Search state QScopedPointer m_entrySearcher; @@ -308,6 +340,7 @@ private: // Autoreload bool m_blockAutoSave; + bool m_reloading; // Autosave delay QPointer m_autosaveTimer; diff --git a/src/gui/DatabaseWidgetStateSync.cpp b/src/gui/DatabaseWidgetStateSync.cpp index 9cc22254f..52458b5ab 100644 --- a/src/gui/DatabaseWidgetStateSync.cpp +++ b/src/gui/DatabaseWidgetStateSync.cpp @@ -33,18 +33,19 @@ DatabaseWidgetStateSync::DatabaseWidgetStateSync(QObject* parent) m_listViewState = config()->get(Config::GUI_ListViewState).toByteArray(); m_searchViewState = config()->get(Config::GUI_SearchViewState).toByteArray(); - connect(qApp, &QCoreApplication::aboutToQuit, this, &DatabaseWidgetStateSync::sync); + m_syncTimer.setSingleShot(true); + m_syncTimer.setInterval(100); + connect(&m_syncTimer, &QTimer::timeout, this, &DatabaseWidgetStateSync::sync); } -DatabaseWidgetStateSync::~DatabaseWidgetStateSync() -{ -} +DatabaseWidgetStateSync::~DatabaseWidgetStateSync() = default; /** * Sync state with persistent storage. */ void DatabaseWidgetStateSync::sync() { + m_syncTimer.stop(); config()->set(Config::GUI_SplitterState, intListToVariant(m_splitterSizes.value(Config::GUI_SplitterState))); config()->set(Config::GUI_PreviewSplitterState, intListToVariant(m_splitterSizes.value(Config::GUI_PreviewSplitterState))); @@ -58,72 +59,71 @@ void DatabaseWidgetStateSync::sync() void DatabaseWidgetStateSync::setActive(DatabaseWidget* dbWidget) { if (m_activeDbWidget) { + if (m_activeDbWidget->currentMode() != DatabaseWidget::Mode::LockedMode) { + // Update settings from previously active database if unlocked + updateAll(); + } disconnect(m_activeDbWidget, nullptr, this, nullptr); } m_activeDbWidget = dbWidget; if (m_activeDbWidget) { - m_blockUpdates = true; - - m_activeDbWidget->setSplitterSizes(m_splitterSizes); - - if (m_activeDbWidget->isSearchActive()) { - restoreSearchView(); - } else { - restoreListView(); + if (m_activeDbWidget->currentMode() != DatabaseWidget::Mode::LockedMode) { + // Immediately apply settings to active database if already unlocked + applySplitterSizes(); + applyViewState(); } - m_blockUpdates = false; - + connect(m_activeDbWidget, SIGNAL(databaseAboutToUnlock()), SLOT(blockUpdates())); + connect(m_activeDbWidget, SIGNAL(databaseUnlocked()), SLOT(applySplitterSizes())); + connect(m_activeDbWidget, SIGNAL(databaseUnlocked()), SLOT(applyViewState())); + connect(m_activeDbWidget, &DatabaseWidget::databaseLocked, this, [this] { updateAll(true); }); connect(m_activeDbWidget, SIGNAL(splitterSizesChanged()), SLOT(updateSplitterSizes())); connect(m_activeDbWidget, SIGNAL(entryViewStateChanged()), SLOT(updateViewState())); - connect(m_activeDbWidget, SIGNAL(listModeActivated()), SLOT(restoreListView())); - connect(m_activeDbWidget, SIGNAL(searchModeActivated()), SLOT(restoreSearchView())); + connect(m_activeDbWidget, SIGNAL(listModeActivated()), SLOT(applyViewState())); + connect(m_activeDbWidget, SIGNAL(searchModeActivated()), SLOT(applyViewState())); connect(m_activeDbWidget, SIGNAL(listModeAboutToActivate()), SLOT(blockUpdates())); connect(m_activeDbWidget, SIGNAL(searchModeAboutToActivate()), SLOT(blockUpdates())); } } +void DatabaseWidgetStateSync::applySplitterSizes() +{ + if (!m_activeDbWidget) { + return; + } + + m_blockUpdates = true; + + m_activeDbWidget->setSplitterSizes(m_splitterSizes); + + m_blockUpdates = false; +} + /** * Restore entry view list view state * * NOTE: - * States of entry view 'Hide Usernames'/'Hide Passwords' settings are global, - * i.e. they are the same for both list and search mode - * - * NOTE: * If m_listViewState is empty, the list view has been activated for the first * time after starting with a clean (or invalid) config. */ -void DatabaseWidgetStateSync::restoreListView() +void DatabaseWidgetStateSync::applyViewState() { - if (!m_listViewState.isEmpty()) { - m_activeDbWidget->setEntryViewState(m_listViewState); + if (!m_activeDbWidget) { + return; } - m_blockUpdates = false; -} + m_blockUpdates = true; -/** - * Restore entry view search view state - * - * NOTE: - * States of entry view 'Hide Usernames'/'Hide Passwords' settings are global, - * i.e. they are the same for both list and search mode - * - * NOTE: - * If m_searchViewState is empty, the search view has been activated for the - * first time after starting with a clean (or invalid) config. Thus, save the - * current state. Without this, m_searchViewState would remain empty until - * there is an actual view state change (e.g. column is resized) - */ -void DatabaseWidgetStateSync::restoreSearchView() -{ - if (!m_searchViewState.isEmpty()) { - m_activeDbWidget->setEntryViewState(m_searchViewState); + if (m_activeDbWidget->isSearchActive()) { + if (!m_searchViewState.isEmpty()) { + m_activeDbWidget->setEntryViewState(m_searchViewState); + } } else { - m_searchViewState = m_activeDbWidget->entryViewState(); + if (!m_listViewState.isEmpty()) { + m_activeDbWidget->setEntryViewState(m_listViewState); + } } m_blockUpdates = false; @@ -134,19 +134,25 @@ void DatabaseWidgetStateSync::blockUpdates() m_blockUpdates = true; } +void DatabaseWidgetStateSync::updateAll(bool forceSync) +{ + updateSplitterSizes(); + updateViewState(); + if (forceSync) { + sync(); + } +} + void DatabaseWidgetStateSync::updateSplitterSizes() { if (!m_blockUpdates) { m_splitterSizes = m_activeDbWidget->splitterSizes(); + m_syncTimer.start(); } } /** * Update entry view list/search view state - * - * NOTE: - * States of entry view 'Hide Usernames'/'Hide Passwords' settings are global, - * i.e. they are the same for both list and search mode */ void DatabaseWidgetStateSync::updateViewState() { @@ -160,7 +166,7 @@ void DatabaseWidgetStateSync::updateViewState() m_listViewState = m_activeDbWidget->entryViewState(); } - sync(); + m_syncTimer.start(); } QList DatabaseWidgetStateSync::variantToIntList(const QVariant& variant) diff --git a/src/gui/DatabaseWidgetStateSync.h b/src/gui/DatabaseWidgetStateSync.h index 8f8aef6dc..b9e53fdc6 100644 --- a/src/gui/DatabaseWidgetStateSync.h +++ b/src/gui/DatabaseWidgetStateSync.h @@ -32,13 +32,14 @@ public: public slots: void setActive(DatabaseWidget* dbWidget); - void restoreListView(); - void restoreSearchView(); + void applySplitterSizes(); + void applyViewState(); private slots: void blockUpdates(); void updateSplitterSizes(); void updateViewState(); + void updateAll(bool forceSync = false); void sync(); private: @@ -48,6 +49,8 @@ private: QPointer m_activeDbWidget; bool m_blockUpdates; + QTimer m_syncTimer; + QHash> m_splitterSizes; QByteArray m_listViewState; diff --git a/src/gui/EditWidget.cpp b/src/gui/EditWidget.cpp index 0c4e80698..1a79d9bad 100644 --- a/src/gui/EditWidget.cpp +++ b/src/gui/EditWidget.cpp @@ -31,6 +31,7 @@ EditWidget::EditWidget(QWidget* parent) setModified(false); m_ui->messageWidget->setHidden(true); + m_ui->headerLabel->setHidden(true); QFont headerLabelFont = m_ui->headerLabel->font(); headerLabelFont.setBold(true); @@ -45,9 +46,7 @@ EditWidget::EditWidget(QWidget* parent) connect(m_ui->buttonBox, SIGNAL(clicked(QAbstractButton*)), SLOT(buttonClicked(QAbstractButton*))); } -EditWidget::~EditWidget() -{ -} +EditWidget::~EditWidget() = default; void EditWidget::addPage(const QString& labelText, const QIcon& icon, QWidget* widget) { @@ -72,16 +71,25 @@ void EditWidget::addPage(const QString& labelText, const QIcon& icon, QWidget* w m_ui->categoryList->addCategory(labelText, icon); } -bool EditWidget::hasPage(QWidget* widget) +bool EditWidget::hasPage(const QWidget* widget) const { + return pageIndex(widget) >= 0; +} + +int EditWidget::pageIndex(const QWidget* widget) const +{ + if (!widget) { + return -1; + } + for (int i = 0; i < m_ui->stackedWidget->count(); i++) { auto* scrollArea = qobject_cast(m_ui->stackedWidget->widget(i)); - if (scrollArea && scrollArea->widget() == widget) { - return true; + if (scrollArea && (scrollArea == widget || scrollArea->widget() == widget)) { + return i; } } - return false; + return -1; } void EditWidget::setPageHidden(QWidget* widget, bool hidden) @@ -120,6 +128,7 @@ void EditWidget::setCurrentPage(int index) void EditWidget::setHeadline(const QString& text) { + m_ui->headerLabel->setHidden(text.isEmpty()); m_ui->headerLabel->setText(text); } diff --git a/src/gui/EditWidget.h b/src/gui/EditWidget.h index c4997abae..4839d5877 100644 --- a/src/gui/EditWidget.h +++ b/src/gui/EditWidget.h @@ -39,10 +39,11 @@ class EditWidget : public DialogyWidget public: explicit EditWidget(QWidget* parent = nullptr); - ~EditWidget(); + ~EditWidget() override; void addPage(const QString& labelText, const QIcon& icon, QWidget* widget); - bool hasPage(QWidget* widget); + bool hasPage(const QWidget* widget) const; + int pageIndex(const QWidget* widget) const; void setPageHidden(QWidget* widget, bool hidden); void setCurrentPage(int index); void setHeadline(const QString& text); diff --git a/src/gui/EditWidgetIcons.cpp b/src/gui/EditWidgetIcons.cpp index c91974c4c..f23d14ce7 100644 --- a/src/gui/EditWidgetIcons.cpp +++ b/src/gui/EditWidgetIcons.cpp @@ -86,9 +86,7 @@ EditWidgetIcons::EditWidgetIcons(QWidget* parent) #endif } -EditWidgetIcons::~EditWidgetIcons() -{ -} +EditWidgetIcons::~EditWidgetIcons() = default; IconStruct EditWidgetIcons::state() { diff --git a/src/gui/EditWidgetIcons.h b/src/gui/EditWidgetIcons.h index 15e927d6c..3b40fae41 100644 --- a/src/gui/EditWidgetIcons.h +++ b/src/gui/EditWidgetIcons.h @@ -62,7 +62,7 @@ class EditWidgetIcons : public QWidget public: explicit EditWidgetIcons(QWidget* parent = nullptr); - ~EditWidgetIcons(); + ~EditWidgetIcons() override; IconStruct state(); void reset(); diff --git a/src/gui/EditWidgetProperties.cpp b/src/gui/EditWidgetProperties.cpp index 3e26352d3..4aea1510c 100644 --- a/src/gui/EditWidgetProperties.cpp +++ b/src/gui/EditWidgetProperties.cpp @@ -41,9 +41,7 @@ EditWidgetProperties::EditWidgetProperties(QWidget* parent) connect(m_ui->removeCustomDataButton, SIGNAL(clicked()), SLOT(removeSelectedPluginData())); } -EditWidgetProperties::~EditWidgetProperties() -{ -} +EditWidgetProperties::~EditWidgetProperties() = default; void EditWidgetProperties::setFields(const TimeInfo& timeInfo, const QUuid& uuid) { diff --git a/src/gui/EditWidgetProperties.h b/src/gui/EditWidgetProperties.h index 30a983e98..679a14501 100644 --- a/src/gui/EditWidgetProperties.h +++ b/src/gui/EditWidgetProperties.h @@ -38,7 +38,7 @@ class EditWidgetProperties : public QWidget public: explicit EditWidgetProperties(QWidget* parent = nullptr); - ~EditWidgetProperties(); + ~EditWidgetProperties() override; void setFields(const TimeInfo& timeInfo, const QUuid& uuid); void setCustomData(CustomData* customData); diff --git a/src/gui/EditWidgetProperties.ui b/src/gui/EditWidgetProperties.ui index 0caa9ef27..510e4fffa 100644 --- a/src/gui/EditWidgetProperties.ui +++ b/src/gui/EditWidgetProperties.ui @@ -58,7 +58,7 @@
    - + Modified: diff --git a/src/gui/EntryPreviewWidget.cpp b/src/gui/EntryPreviewWidget.cpp index 3ae0dc08b..02ab3622f 100644 --- a/src/gui/EntryPreviewWidget.cpp +++ b/src/gui/EntryPreviewWidget.cpp @@ -20,9 +20,9 @@ #include "ui_EntryPreviewWidget.h" #include "Application.h" +#include "core/Clock.h" #include "core/Config.h" #include "core/Totp.h" -#include "gui/Clipboard.h" #include "gui/Font.h" #include "gui/Icons.h" #if defined(WITH_XC_KEESHARE) @@ -50,7 +50,7 @@ EntryPreviewWidget::EntryPreviewWidget(QWidget* parent) // Entry m_ui->entryTotpButton->setIcon(icons()->icon("totp")); - m_ui->entryCloseButton->setIcon(icons()->icon("dialog-close")); + m_ui->entryCloseButton->setIcon(icons()->icon("arrow-collapse-down")); m_ui->toggleUsernameButton->setIcon(icons()->onOffIcon("password-show", true)); m_ui->togglePasswordButton->setIcon(icons()->onOffIcon("password-show", true)); m_ui->toggleEntryNotesButton->setIcon(icons()->onOffIcon("password-show", true)); @@ -70,8 +70,7 @@ EntryPreviewWidget::EntryPreviewWidget(QWidget* parent) m_ui->entryTotpLabel->installEventFilter(this); - connect(m_ui->entryTotpButton, SIGNAL(toggled(bool)), m_ui->entryTotpLabel, SLOT(setVisible(bool))); - connect(m_ui->entryTotpButton, SIGNAL(toggled(bool)), m_ui->entryTotpProgress, SLOT(setVisible(bool))); + connect(m_ui->entryTotpButton, SIGNAL(toggled(bool)), m_ui->entryTotp, SLOT(setVisible(bool))); connect(m_ui->entryCloseButton, SIGNAL(clicked()), SLOT(hide())); connect(m_ui->toggleUsernameButton, SIGNAL(clicked(bool)), SLOT(setUsernameVisible(bool))); connect(m_ui->togglePasswordButton, SIGNAL(clicked(bool)), SLOT(setPasswordVisible(bool))); @@ -85,16 +84,18 @@ EntryPreviewWidget::EntryPreviewWidget(QWidget* parent) }); connect(&m_totpTimer, SIGNAL(timeout()), SLOT(updateTotpLabel())); - connect(m_ui->entryAttributesTable, &QTableWidget::itemDoubleClicked, this, [](QTableWidgetItem* item) { + connect(m_ui->entryAttributesTable, &QTableWidget::itemDoubleClicked, this, [this](QTableWidgetItem* item) { auto userData = item->data(Qt::UserRole); if (userData.isValid()) { - clipboard()->setText(userData.toString()); + emit copyTextRequested(userData.toString()); } }); connect(config(), &Config::changed, this, [this](Config::ConfigKey key) { if (key == Config::GUI_HidePreviewPanel) { setVisible(!config()->get(Config::GUI_HidePreviewPanel).toBool()); + } else if (key == Config::Security_HideTotpPreviewPanel) { + m_ui->entryTotpButton->setChecked(!config()->get(Config::Security_HideTotpPreviewPanel).toBool()); } refresh(); }); @@ -111,15 +112,13 @@ EntryPreviewWidget::EntryPreviewWidget(QWidget* parent) #endif } -EntryPreviewWidget::~EntryPreviewWidget() -{ -} +EntryPreviewWidget::~EntryPreviewWidget() = default; bool EntryPreviewWidget::eventFilter(QObject* object, QEvent* event) { if (object == m_ui->entryTotpLabel && event->type() == QEvent::MouseButtonDblClick) { if (m_currentEntry && m_currentEntry->hasTotp()) { - clipboard()->setText(m_currentEntry->totp()); + emit copyTextRequested(m_currentEntry->totp()); m_ui->entryTotpLabel->clearFocus(); return true; } @@ -261,9 +260,9 @@ void EntryPreviewWidget::updateEntryTotp() m_totpTimer.start(1000); m_ui->entryTotpProgress->setMaximum(m_currentEntry->totpSettings()->step); updateTotpLabel(); + m_ui->entryTotp->setVisible(m_ui->entryTotpButton->isChecked()); } else { - m_ui->entryTotpLabel->hide(); - m_ui->entryTotpProgress->hide(); + m_ui->entryTotp->hide(); m_ui->entryTotpButton->setChecked(false); m_ui->entryTotpLabel->clear(); m_totpTimer.stop(); @@ -304,9 +303,11 @@ void EntryPreviewWidget::setPasswordVisible(bool state) html += "" + QString(c).toHtmlEscaped() + ""; } // clang-format on + m_ui->entryPasswordLabel->setTextFormat(Qt::RichText); m_ui->entryPasswordLabel->setText(html); } else { // No color + m_ui->entryPasswordLabel->setTextFormat(Qt::PlainText); m_ui->entryPasswordLabel->setText(password); } } else if (password.isEmpty() && !config()->get(Config::Security_PasswordEmptyPlaceholder).toBool()) { @@ -323,7 +324,8 @@ void EntryPreviewWidget::setPasswordVisible(bool state) void EntryPreviewWidget::setEntryNotesVisible(bool state) { - setNotesVisible(m_ui->entryNotesTextEdit, m_currentEntry->notes(), state); + setNotesVisible( + m_ui->entryNotesTextEdit, m_currentEntry->resolveMultiplePlaceholders(m_currentEntry->notes()), state); m_ui->toggleEntryNotesButton->setIcon(icons()->onOffIcon("password-show", state)); } @@ -388,7 +390,7 @@ void EntryPreviewWidget::updateEntryGeneralTab() m_ui->entryNotesTextEdit->setFont(Font::defaultFont()); } - m_ui->entryUrlLabel->setRawText(m_currentEntry->displayUrl()); + m_ui->entryUrlLabel->setRawText(m_currentEntry->displayUrl().toHtmlEscaped()); const QString url = m_currentEntry->url(); if (!url.isEmpty()) { // URL is well formed and can be opened in a browser @@ -401,8 +403,7 @@ void EntryPreviewWidget::updateEntryGeneralTab() } const TimeInfo entryTime = m_currentEntry->timeInfo(); - const QString expires = - entryTime.expires() ? entryTime.expiryTime().toLocalTime().toString(Qt::DefaultLocaleShortDate) : tr("Never"); + const QString expires = entryTime.expires() ? Clock::toString(entryTime.expiryTime().toLocalTime()) : tr("Never"); m_ui->entryExpirationLabel->setText(expires); m_ui->entryTagsList->tags(m_currentEntry->tagList()); m_ui->entryTagsList->setReadOnly(true); @@ -430,6 +431,8 @@ void EntryPreviewWidget::updateEntryAdvancedTab() m_ui->entryAttributesTable->item(i, 0)->setFont(font); m_ui->entryAttributesTable->item(i, 0)->setTextAlignment(Qt::AlignTop | Qt::AlignLeft); + auto value = m_currentEntry->resolveMultiplePlaceholders(attributes->value(key)); + if (attributes->isProtected(key)) { // only show the reveal button on protected attributes auto button = new QToolButton(); @@ -456,10 +459,10 @@ void EntryPreviewWidget::updateEntryAdvancedTab() m_ui->entryAttributesTable->setCellWidget(i, 1, button); m_ui->entryAttributesTable->setItem(i, 2, new QTableWidgetItem(QString("\u25cf").repeated(6))); } else { - m_ui->entryAttributesTable->setItem(i, 2, new QTableWidgetItem(attributes->value(key))); + m_ui->entryAttributesTable->setItem(i, 2, new QTableWidgetItem(value)); } - m_ui->entryAttributesTable->item(i, 2)->setData(Qt::UserRole, attributes->value(key)); + m_ui->entryAttributesTable->item(i, 2)->setData(Qt::UserRole, value); m_ui->entryAttributesTable->item(i, 2)->setToolTip(tr("Double click to copy value")); m_ui->entryAttributesTable->item(i, 2)->setTextAlignment(Qt::AlignTop | Qt::AlignLeft); @@ -511,8 +514,7 @@ void EntryPreviewWidget::updateGroupGeneralTab() m_ui->groupAutotypeLabel->setText(autotypeText); const TimeInfo groupTime = m_currentGroup->timeInfo(); - const QString expiresText = - groupTime.expires() ? groupTime.expiryTime().toString(Qt::DefaultLocaleShortDate) : tr("Never"); + const QString expiresText = groupTime.expires() ? Clock::toString(groupTime.expiryTime()) : tr("Never"); m_ui->groupExpirationLabel->setText(expiresText); if (config()->get(Config::Security_HideNotes).toBool()) { @@ -545,16 +547,23 @@ void EntryPreviewWidget::updateGroupSharingTab() void EntryPreviewWidget::updateTotpLabel() { if (!m_locked && m_currentEntry && m_currentEntry->hasTotp()) { - auto totpCode = m_currentEntry->totp(); - totpCode.insert(totpCode.size() / 2, " "); - m_ui->entryTotpLabel->setText(totpCode); + bool isValid = false; + auto totpCode = m_currentEntry->totp(&isValid); + if (isValid) { + totpCode.insert(totpCode.size() / 2, " "); - auto step = m_currentEntry->totpSettings()->step; - auto timeleft = step - (Clock::currentSecondsSinceEpoch() % step); - m_ui->entryTotpProgress->setValue(timeleft); - m_ui->entryTotpProgress->update(); + auto step = m_currentEntry->totpSettings()->step; + auto timeleft = step - (Clock::currentSecondsSinceEpoch() % step); + m_ui->entryTotpProgress->setValue(timeleft); + m_ui->entryTotpProgress->update(); + } else { + m_totpTimer.stop(); + } + + m_ui->entryTotpProgress->setVisible(isValid); + m_ui->entryTotpLabel->setText(totpCode); } else { - m_ui->entryTotpLabel->clear(); + m_ui->entryTotp->setVisible(false); m_totpTimer.stop(); } } diff --git a/src/gui/EntryPreviewWidget.h b/src/gui/EntryPreviewWidget.h index 83af07ee9..b5c497a76 100644 --- a/src/gui/EntryPreviewWidget.h +++ b/src/gui/EntryPreviewWidget.h @@ -46,6 +46,7 @@ public slots: signals: void entryUrlActivated(Entry* entry); + void copyTextRequested(const QString& text); protected: bool eventFilter(QObject* object, QEvent* event) override; diff --git a/src/gui/EntryPreviewWidget.ui b/src/gui/EntryPreviewWidget.ui index 92081ab18..e44218b3e 100644 --- a/src/gui/EntryPreviewWidget.ui +++ b/src/gui/EntryPreviewWidget.ui @@ -100,7 +100,7 @@ Qt::ClickFocus - Qt::AutoText + Qt::PlainText Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse @@ -110,47 +110,66 @@ - - - 0 + + + + 0 + 0 + - - - - - 10 - 75 - true - - - - Double click to copy to clipboard - - - 1234567 - - - Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse - - - - - - - - 57 - 4 - - - - 50 - - - false - - - - + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 10 + true + + + + Double click to copy to clipboard + + + 1234567 + + + Qt::TextInteractionFlag::LinksAccessibleByMouse|Qt::TextInteractionFlag::TextSelectableByKeyboard|Qt::TextInteractionFlag::TextSelectableByMouse + + + + + + + + 57 + 4 + + + + 50 + + + false + + + + + @@ -279,12 +298,18 @@ + + Qt::ClickFocus + TextLabel Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse + + true + @@ -316,9 +341,15 @@ https://example.com + + Qt::RichText + Qt::TextBrowserInteraction + + true + @@ -403,6 +434,12 @@ true + + 10.000000000000000 + + + true + @@ -476,6 +513,9 @@ true + + true + @@ -488,6 +528,9 @@ Tags list + + true + @@ -504,9 +547,15 @@ expired + + Qt::PlainText + Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse + + true + @@ -1100,6 +1149,9 @@ true + + true + diff --git a/src/gui/FileDialog.cpp b/src/gui/FileDialog.cpp index 5129e2755..96ee2b206 100644 --- a/src/gui/FileDialog.cpp +++ b/src/gui/FileDialog.cpp @@ -23,9 +23,7 @@ FileDialog* FileDialog::m_instance(nullptr); -FileDialog::FileDialog() -{ -} +FileDialog::FileDialog() = default; QString FileDialog::getOpenFileName(QWidget* parent, const QString& caption, diff --git a/src/gui/Font.cpp b/src/gui/Font.cpp index 352abea8c..bb02b12ac 100644 --- a/src/gui/Font.cpp +++ b/src/gui/Font.cpp @@ -28,19 +28,21 @@ QFont Font::defaultFont() QFont Font::fixedFont() { auto fixedFont = QFontDatabase::systemFont(QFontDatabase::FixedFont); + fixedFont.setPointSize(defaultFont().pointSize()); #ifdef Q_OS_WIN // try to use Consolas on Windows, because the default Courier New has too many similar characters - auto consolasFont = QFontDatabase().font("Consolas", fixedFont.styleName(), fixedFont.pointSize()); + auto consolasFont = QFontDatabase().font("Consolas", fixedFont.styleName(), defaultFont().pointSize()); if (consolasFont.family().contains("consolas", Qt::CaseInsensitive)) { fixedFont = consolasFont; - // Bump up the font size by one point to match the default font - fixedFont.setPointSize(fixedFont.pointSize() + 1); + // Bump up the font size by one point to better match the default font on Windows + fixedFont.setPointSize(defaultFont().pointSize() + 1); } #endif #ifdef Q_OS_MACOS // Qt doesn't choose a monospace font correctly on macOS - fixedFont = QFontDatabase().font("Menlo", fixedFont.styleName(), fixedFont.pointSize()); + fixedFont = QFontDatabase().font("Menlo", fixedFont.styleName(), defaultFont().pointSize()); + fixedFont.setPointSize(defaultFont().pointSize()); #endif return fixedFont; } diff --git a/src/gui/Font.h b/src/gui/Font.h index d53f0c407..878dbb53d 100644 --- a/src/gui/Font.h +++ b/src/gui/Font.h @@ -27,9 +27,7 @@ public: static QFont fixedFont(); private: - Font() - { - } + Font() = default; }; #endif // KEEPASSX_FONT_H diff --git a/src/gui/GuiTools.cpp b/src/gui/GuiTools.cpp index 30963b374..b2dfa63f3 100644 --- a/src/gui/GuiTools.cpp +++ b/src/gui/GuiTools.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2021 KeePassXC Team + * Copyright (C) 2024 KeePassXC Team * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -66,6 +66,21 @@ namespace GuiTools } } + bool confirmDeletePluginData(QWidget* parent, const QList& entries) + { + if (!parent || entries.isEmpty()) { + return false; + } + + auto answer = MessageBox::question(parent, + QObject::tr("Delete plugin data?"), + QObject::tr("Delete plugin data from Entry(s)?", "", entries.size()), + MessageBox::Delete | MessageBox::Cancel, + MessageBox::Cancel); + + return answer == MessageBox::Delete; + } + size_t deleteEntriesResolveReferences(QWidget* parent, const QList& entries, bool permanent) { if (!parent || entries.isEmpty()) { diff --git a/src/gui/GuiTools.h b/src/gui/GuiTools.h index 814537382..c5e710896 100644 --- a/src/gui/GuiTools.h +++ b/src/gui/GuiTools.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2021 KeePassXC Team + * Copyright (C) 2024 KeePassXC Team * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -26,6 +26,7 @@ class Entry; namespace GuiTools { bool confirmDeleteEntries(QWidget* parent, const QList& entries, bool permanent); + bool confirmDeletePluginData(QWidget* parent, const QList& entries); size_t deleteEntriesResolveReferences(QWidget* parent, const QList& entries, bool permanent); } // namespace GuiTools #endif // KEEPASSXC_GUITOOLS_H diff --git a/src/gui/HtmlGuiExporter.cpp b/src/gui/HtmlGuiExporter.cpp new file mode 100644 index 000000000..75175e3f0 --- /dev/null +++ b/src/gui/HtmlGuiExporter.cpp @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2019 KeePassXC Team + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 or (at your option) + * version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "HtmlGuiExporter.h" + +#include + +#include "gui/Icons.h" + +namespace +{ + QString PixmapToHTML(const QPixmap& pixmap) + { + if (pixmap.isNull()) { + return ""; + } + + // Based on https://stackoverflow.com/a/6621278 + QByteArray a; + QBuffer buffer(&a); + pixmap.save(&buffer, "PNG"); + return QString(""; + } +} // namespace + +QString HtmlGuiExporter::groupIconToHtml(const Group* group) +{ + return PixmapToHTML(Icons::groupIconPixmap(group, IconSize::Medium)); +} + +QString HtmlGuiExporter::entryIconToHtml(const Entry* entry) +{ + return PixmapToHTML(Icons::entryIconPixmap(entry, IconSize::Medium)); +} diff --git a/src/gui/HtmlGuiExporter.h b/src/gui/HtmlGuiExporter.h new file mode 100644 index 000000000..9979996a1 --- /dev/null +++ b/src/gui/HtmlGuiExporter.h @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2019 KeePassXC Team + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 or (at your option) + * version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef KEEPASSX_HTMLGUIEXPORTER_H +#define KEEPASSX_HTMLGUIEXPORTER_H + +#include "format/HtmlExporter.h" + +class HtmlGuiExporter : public HtmlExporter +{ +protected: + QString groupIconToHtml(const Group* group) override; + QString entryIconToHtml(const Entry* entry) override; +}; + +#endif // KEEPASSX_HTMLGUIEXPORTER_H diff --git a/src/gui/IconDownloader.cpp b/src/gui/IconDownloader.cpp index 1adb26922..b07856862 100644 --- a/src/gui/IconDownloader.cpp +++ b/src/gui/IconDownloader.cpp @@ -17,8 +17,8 @@ #include "IconDownloader.h" #include "core/Config.h" -#include "core/NetworkManager.h" -#include "core/UrlTools.h" +#include "gui/UrlTools.h" +#include "networking/NetworkManager.h" #include #include @@ -75,9 +75,9 @@ void IconDownloader::setUrl(const QString& entryUrl) // Determine if host portion of URL is an IP address by resolving it and // searching for a match with the returned address(es). bool hostIsIp = false; - QList hostAddressess = QHostInfo::fromName(fullyQualifiedDomain).addresses(); + QList hostAddresses = QHostInfo::fromName(fullyQualifiedDomain).addresses(); hostIsIp = - std::any_of(hostAddressess.begin(), hostAddressess.end(), [&fullyQualifiedDomain](const QHostAddress& addr) { + std::any_of(hostAddresses.begin(), hostAddresses.end(), [&fullyQualifiedDomain](const QHostAddress& addr) { return addr.toString() == fullyQualifiedDomain; }); diff --git a/src/gui/IconDownloader.h b/src/gui/IconDownloader.h index 54d9295e8..8d32f787f 100644 --- a/src/gui/IconDownloader.h +++ b/src/gui/IconDownloader.h @@ -60,4 +60,4 @@ private: friend class TestIconDownloader; }; -#endif // KEEPASSXC_ICONDOWNLOADER_H \ No newline at end of file +#endif // KEEPASSXC_ICONDOWNLOADER_H diff --git a/src/gui/IconDownloaderDialog.cpp b/src/gui/IconDownloaderDialog.cpp index 929146bd3..72e96785b 100644 --- a/src/gui/IconDownloaderDialog.cpp +++ b/src/gui/IconDownloaderDialog.cpp @@ -38,7 +38,6 @@ IconDownloaderDialog::IconDownloaderDialog(QWidget* parent) , m_ui(new Ui::IconDownloaderDialog()) , m_dataModel(new QStandardItemModel(this)) { - setWindowFlags(Qt::Window); setAttribute(Qt::WA_DeleteOnClose); m_ui->setupUi(this); diff --git a/src/gui/IconModels.cpp b/src/gui/IconModels.cpp index ab435aedc..1d1eefb42 100644 --- a/src/gui/IconModels.cpp +++ b/src/gui/IconModels.cpp @@ -38,7 +38,7 @@ int DefaultIconModel::rowCount(const QModelIndex& parent) const QVariant DefaultIconModel::data(const QModelIndex& index, int role) const { if (!index.isValid()) { - return QVariant(); + return {}; } Q_ASSERT(index.row() < databaseIcons()->count()); @@ -47,7 +47,7 @@ QVariant DefaultIconModel::data(const QModelIndex& index, int role) const return databaseIcons()->icon(index.row(), IconSize::Medium); } - return QVariant(); + return {}; } CustomIconModel::CustomIconModel(QObject* parent) @@ -78,7 +78,7 @@ int CustomIconModel::rowCount(const QModelIndex& parent) const QVariant CustomIconModel::data(const QModelIndex& index, int role) const { if (!index.isValid()) { - return QVariant(); + return {}; } if (role == Qt::DecorationRole) { @@ -86,7 +86,7 @@ QVariant CustomIconModel::data(const QModelIndex& index, int role) const return m_icons.value(uuid); } - return QVariant(); + return {}; } QUuid CustomIconModel::uuidFromIndex(const QModelIndex& index) const diff --git a/src/gui/Icons.cpp b/src/gui/Icons.cpp index 194c6625d..7cccf406a 100644 --- a/src/gui/Icons.cpp +++ b/src/gui/Icons.cpp @@ -50,16 +50,14 @@ private: Icons* Icons::m_instance(nullptr); -Icons::Icons() -{ -} +Icons::Icons() = default; QString Icons::applicationIconName() { #ifdef KEEPASSXC_DIST_FLATPAK - return QString("org.keepassxc.KeePassXC"); + return "org.keepassxc.KeePassXC"; #else - return QString("keepassxc"); + return "keepassxc"; #endif } @@ -88,8 +86,8 @@ QIcon Icons::trayIcon(bool unlocked) suffix = "-locked"; } - auto iconApperance = trayIconAppearance(); - if (!iconApperance.startsWith("monochrome")) { + auto iconAppearance = trayIconAppearance(); + if (!iconAppearance.startsWith("monochrome")) { return icon(QString("%1%2").arg(applicationIconName(), suffix), false); } @@ -101,15 +99,13 @@ QIcon Icons::trayIcon(bool unlocked) i = icon(QString("keepassxc-monochrome-dark%1").arg(suffix), false); } #else - i = icon(QString("%1-%2%3").arg(applicationIconName(), iconApperance, suffix), false); + i = icon(QString("%1-%2%3").arg(applicationIconName(), iconAppearance, suffix), false); #endif -#if QT_VERSION >= QT_VERSION_CHECK(5, 6, 0) // Set as mask to allow the operating system to recolour the tray icon. This may look weird // if we failed to detect the status bar background colour correctly, but it is certainly // better than a barely visible icon and even if we did guess correctly, it allows for better // integration should the system's preferred colours not be 100% black or white. i.setIsMask(true); -#endif return i; } @@ -123,11 +119,7 @@ AdaptiveIconEngine::AdaptiveIconEngine(QIcon baseIcon, QColor overrideColor) void AdaptiveIconEngine::paint(QPainter* painter, const QRect& rect, QIcon::Mode mode, QIcon::State state) { // Temporary image canvas to ensure that the background is transparent and alpha blending works. -#if QT_VERSION >= QT_VERSION_CHECK(5, 6, 0) auto scale = painter->device()->devicePixelRatioF(); -#else - auto scale = painter->device()->devicePixelRatio(); -#endif QImage img(rect.size() * scale, QImage::Format_ARGB32_Premultiplied); img.fill(0); QPainter p(&img); @@ -193,9 +185,7 @@ QIcon Icons::icon(const QString& name, bool recolor, const QColor& overrideColor icon = QIcon::fromTheme(name); if (recolor) { icon = QIcon(new AdaptiveIconEngine(icon, overrideColor)); -#if QT_VERSION >= QT_VERSION_CHECK(5, 6, 0) icon.setIsMask(true); -#endif } m_iconCache.insert(cacheName, icon); diff --git a/src/gui/KMessageWidget.cpp b/src/gui/KMessageWidget.cpp index a7e723692..6b402f313 100644 --- a/src/gui/KMessageWidget.cpp +++ b/src/gui/KMessageWidget.cpp @@ -88,7 +88,7 @@ void KMessageWidgetPrivate::init(KMessageWidget *q_ptr) QObject::connect(textLabel, SIGNAL(linkActivated(QString)), q, SIGNAL(linkActivated(QString))); QObject::connect(textLabel, SIGNAL(linkHovered(QString)), q, SIGNAL(linkHovered(QString))); - QAction *closeAction = new QAction(q); + auto closeAction = new QAction(q); closeAction->setText(KMessageWidget::tr("&Close")); closeAction->setToolTip(KMessageWidget::tr("Close message")); closeAction->setIcon(icons()->icon("message-close")); @@ -114,7 +114,7 @@ void KMessageWidgetPrivate::createLayout() const auto actions = q->actions(); for (QAction *action: actions) { - QToolButton *button = new QToolButton(content); + auto button = new QToolButton(content); button->setDefaultAction(action); button->setToolButtonStyle(Qt::ToolButtonTextBesideIcon); buttons.append(button); @@ -126,12 +126,12 @@ void KMessageWidgetPrivate::createLayout() closeButton->setAutoRaise(buttons.isEmpty()); if (wordWrap) { - QGridLayout *layout = new QGridLayout(content); + auto layout = new QGridLayout(content); // Set alignment to make sure icon does not move down if text wraps layout->addWidget(iconLabel, 0, 0, 1, 1, Qt::AlignHCenter | Qt::AlignTop); layout->addWidget(textLabel, 0, 1); - QHBoxLayout *buttonLayout = new QHBoxLayout; + auto buttonLayout = new QHBoxLayout; buttonLayout->addStretch(); for (QToolButton* button: asConst(buttons)) { // For some reason, calling show() is necessary if wordwrap is true, @@ -143,7 +143,7 @@ void KMessageWidgetPrivate::createLayout() buttonLayout->addWidget(closeButton); layout->addItem(buttonLayout, 1, 0, 1, 2); } else { - QHBoxLayout *layout = new QHBoxLayout(content); + auto layout = new QHBoxLayout(content); layout->addWidget(iconLabel); layout->addWidget(textLabel); @@ -280,7 +280,11 @@ void KMessageWidget::setMessageType(KMessageWidget::MessageType type) auto closeButtonPixmap = d->closeButtonPixmap; QPainter painter; painter.begin(&closeButtonPixmap); +#if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0) + painter.setRenderHints(QPainter::Antialiasing); +#else painter.setRenderHints(QPainter::HighQualityAntialiasing); +#endif painter.setCompositionMode(QPainter::CompositionMode_SourceIn); painter.fillRect(QRect(0, 0, 16, 16), fg); painter.end(); diff --git a/src/gui/KMessageWidget.h b/src/gui/KMessageWidget.h index d47e78f9c..d97089ac9 100644 --- a/src/gui/KMessageWidget.h +++ b/src/gui/KMessageWidget.h @@ -119,19 +119,19 @@ public: /** * Constructs a KMessageWidget with the specified @p parent. */ - explicit KMessageWidget(QWidget *parent = 0); - + explicit KMessageWidget(QWidget* parent = nullptr); + /** * Constructs a KMessageWidget with the specified @p parent and * contents @p text. */ - explicit KMessageWidget(const QString &text, QWidget *parent = 0); - + explicit KMessageWidget(const QString& text, QWidget* parent = nullptr); + /** * Destructor. */ - ~KMessageWidget(); - + ~KMessageWidget() override; + /** * Get the text of this message widget. * @see setText() diff --git a/src/gui/MainWindow.cpp b/src/gui/MainWindow.cpp index cc7673fb6..3abb8f12f 100644 --- a/src/gui/MainWindow.cpp +++ b/src/gui/MainWindow.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2023 KeePassXC Team + * Copyright (C) 2024 KeePassXC Team * Copyright (C) 2010 Felix Geyer * * This program is free software: you can redistribute it and/or modify @@ -38,17 +38,19 @@ #include "autotype/AutoType.h" #include "core/InactivityTimer.h" #include "core/Resources.h" -#include "core/Tools.h" #include "gui/AboutDialog.h" +#include "gui/ActionCollection.h" #include "gui/Icons.h" #include "gui/MessageBox.h" #include "gui/SearchWidget.h" +#include "gui/ShortcutSettingsPage.h" #include "gui/entry/EntryView.h" #include "gui/osutils/OSUtils.h" +#include "gui/remote/RemoteSettings.h" #ifdef WITH_XC_UPDATECHECK #include "gui/UpdateCheckDialog.h" -#include "updatecheck/UpdateChecker.h" +#include "networking/UpdateChecker.h" #endif #ifdef WITH_XC_SSHAGENT @@ -70,7 +72,6 @@ #ifdef WITH_XC_BROWSER #include "browser/BrowserService.h" -#include "browser/BrowserSettingsPage.h" #endif #if defined(Q_OS_UNIX) && !defined(Q_OS_MACOS) && !defined(QT_NO_DBUS) @@ -126,6 +127,8 @@ MainWindow::MainWindow() m_entryContextMenu = new QMenu(this); m_entryContextMenu->setSeparatorsCollapsible(true); + m_entryContextMenu->addAction(m_ui->actionEntryRestore); + m_entryContextMenu->addSeparator(); m_entryContextMenu->addAction(m_ui->actionEntryCopyUsername); m_entryContextMenu->addAction(m_ui->actionEntryCopyPassword); m_entryContextMenu->addAction(m_ui->actionEntryCopyURL); @@ -137,9 +140,11 @@ MainWindow::MainWindow() m_entryContextMenu->addSeparator(); #ifdef WITH_XC_BROWSER_PASSKEYS m_entryContextMenu->addAction(m_ui->actionEntryImportPasskey); + m_entryContextMenu->addAction(m_ui->actionEntryRemovePasskey); m_entryContextMenu->addSeparator(); #endif m_entryContextMenu->addAction(m_ui->actionEntryEdit); + m_entryContextMenu->addAction(m_ui->actionEntryExpire); m_entryContextMenu->addAction(m_ui->actionEntryClone); m_entryContextMenu->addAction(m_ui->actionEntryDelete); m_entryContextMenu->addAction(m_ui->actionEntryNew); @@ -152,12 +157,12 @@ MainWindow::MainWindow() m_entryContextMenu->addSeparator(); m_entryContextMenu->addAction(m_ui->actionEntryAddToAgent); m_entryContextMenu->addAction(m_ui->actionEntryRemoveFromAgent); - m_entryContextMenu->addSeparator(); - m_entryContextMenu->addAction(m_ui->actionEntryRestore); m_entryNewContextMenu = new QMenu(this); m_entryNewContextMenu->addAction(m_ui->actionEntryNew); + connect(m_ui->menuRemoteSync, &QMenu::aboutToShow, this, &MainWindow::updateRemoteSyncMenuEntries); + // Build Entry Level Auto-Type menu auto autotypeMenu = new QMenu({}, this); autotypeMenu->addAction(m_ui->actionEntryAutoTypeSequence); @@ -188,9 +193,17 @@ MainWindow::MainWindow() connect(m_ui->tabWidget, &DatabaseTabWidget::databaseLocked, this, &MainWindow::databaseLocked); connect(m_ui->tabWidget, &DatabaseTabWidget::databaseUnlocked, this, &MainWindow::databaseUnlocked); connect(m_ui->tabWidget, &DatabaseTabWidget::activeDatabaseChanged, this, &MainWindow::activeDatabaseChanged); + connect(m_ui->tabWidget, + &DatabaseTabWidget::databaseUnlockDialogFinished, + this, + &MainWindow::databaseUnlockDialogFinished); + + initViewMenu(); + initActionCollection(); + + m_ui->settingsWidget->addSettingsPage(new ShortcutSettingsPage()); #ifdef WITH_XC_BROWSER - m_ui->settingsWidget->addSettingsPage(new BrowserSettingsPage()); connect( browserService(), &BrowserService::requestUnlock, m_ui->tabWidget, &DatabaseTabWidget::performBrowserUnlock); #endif @@ -198,11 +211,12 @@ MainWindow::MainWindow() #ifdef WITH_XC_SSHAGENT connect(sshAgent(), SIGNAL(error(QString)), this, SLOT(showErrorMessage(QString))); connect(sshAgent(), SIGNAL(enabledChanged(bool)), this, SLOT(agentEnabled(bool))); + connect(m_ui->actionClearSSHAgent, SIGNAL(triggered()), SLOT(clearSSHAgent())); m_ui->settingsWidget->addSettingsPage(new AgentSettingsPage()); +#else + agentEnabled(false); #endif - initViewMenu(); - #if defined(WITH_XC_KEESHARE) KeeShare::init(this); m_ui->settingsWidget->addSettingsPage(new SettingsPageKeeShare(m_ui->tabWidget)); @@ -259,53 +273,14 @@ MainWindow::MainWindow() m_ui->actionAllowScreenCapture->setVisible(osUtils->canPreventScreenCapture()); m_inactivityTimer = new InactivityTimer(this); - connect(m_inactivityTimer, SIGNAL(inactivityDetected()), this, SLOT(lockDatabasesAfterInactivity())); + connect(m_inactivityTimer, SIGNAL(inactivityDetected()), this, SLOT(lockAllDatabases())); applySettingsChanges(); - m_ui->actionDatabaseNew->setShortcut(Qt::CTRL + Qt::SHIFT + Qt::Key_N); - setShortcut(m_ui->actionDatabaseOpen, QKeySequence::Open, Qt::CTRL + Qt::Key_O); - setShortcut(m_ui->actionDatabaseSave, QKeySequence::Save, Qt::CTRL + Qt::Key_S); - setShortcut(m_ui->actionDatabaseSaveAs, QKeySequence::SaveAs, Qt::CTRL + Qt::SHIFT + Qt::Key_S); - setShortcut(m_ui->actionDatabaseClose, QKeySequence::Close, Qt::CTRL + Qt::Key_W); - m_ui->actionDatabaseSettings->setShortcut(Qt::CTRL + Qt::SHIFT + Qt::Key_Comma); - m_ui->actionReports->setShortcut(Qt::CTRL + Qt::SHIFT + Qt::Key_R); - setShortcut(m_ui->actionSettings, QKeySequence::Preferences, Qt::CTRL + Qt::Key_Comma); - m_ui->actionLockDatabase->setShortcut(Qt::CTRL + Qt::Key_L); - m_ui->actionLockAllDatabases->setShortcut(Qt::CTRL + Qt::SHIFT + Qt::Key_L); - setShortcut(m_ui->actionQuit, QKeySequence::Quit, Qt::CTRL + Qt::Key_Q); - setShortcut(m_ui->actionEntryNew, QKeySequence::New, Qt::CTRL + Qt::Key_N); - m_ui->actionEntryEdit->setShortcut(Qt::CTRL + Qt::Key_E); - m_ui->actionEntryDelete->setShortcut(Qt::CTRL + Qt::Key_D); - m_ui->actionEntryDelete->setShortcut(Qt::Key_Delete); - m_ui->actionEntryClone->setShortcut(Qt::CTRL + Qt::Key_K); - m_ui->actionEntryTotp->setShortcut(Qt::CTRL + Qt::SHIFT + Qt::Key_T); - m_ui->actionEntryDownloadIcon->setShortcut(Qt::CTRL + Qt::SHIFT + Qt::Key_D); - m_ui->actionEntryCopyTotp->setShortcut(Qt::CTRL + Qt::Key_T); - m_ui->actionEntryCopyPasswordTotp->setShortcut(Qt::CTRL + Qt::Key_Y); - m_ui->actionEntryMoveUp->setShortcut(Qt::CTRL + Qt::ALT + Qt::Key_Up); - m_ui->actionEntryMoveDown->setShortcut(Qt::CTRL + Qt::ALT + Qt::Key_Down); - m_ui->actionEntryCopyUsername->setShortcut(Qt::CTRL + Qt::Key_B); - m_ui->actionEntryCopyPassword->setShortcut(Qt::CTRL + Qt::Key_C); - m_ui->actionEntryCopyTitle->setShortcut(Qt::CTRL + Qt::Key_I); - m_ui->actionEntryAutoTypeSequence->setShortcut(Qt::CTRL + Qt::SHIFT + Qt::Key_V); - m_ui->actionEntryOpenUrl->setShortcut(Qt::CTRL + Qt::SHIFT + Qt::Key_U); - m_ui->actionEntryCopyURL->setShortcut(Qt::CTRL + Qt::Key_U); - m_ui->actionEntryRestore->setShortcut(Qt::CTRL + Qt::Key_R); - - // Prevent conflicts with global Mac shortcuts (force Control on all platforms) -#ifdef Q_OS_MAC - auto modifier = Qt::META; -#else - auto modifier = Qt::CTRL; -#endif - m_ui->actionEntryAddToAgent->setShortcut(modifier + Qt::Key_H); - m_ui->actionEntryRemoveFromAgent->setShortcut(modifier + Qt::SHIFT + Qt::Key_H); - -#if QT_VERSION >= QT_VERSION_CHECK(5, 10, 0) // Qt 5.10 introduced a new "feature" to hide shortcuts in context menus // Unfortunately, Qt::AA_DontShowShortcutsInContextMenus is broken, have to manually enable them m_ui->actionEntryNew->setShortcutVisibleInContextMenu(true); m_ui->actionEntryEdit->setShortcutVisibleInContextMenu(true); + m_ui->actionEntryExpire->setShortcutVisibleInContextMenu(true); m_ui->actionEntryDelete->setShortcutVisibleInContextMenu(true); m_ui->actionEntryRestore->setShortcutVisibleInContextMenu(true); m_ui->actionEntryClone->setShortcutVisibleInContextMenu(true); @@ -323,7 +298,6 @@ MainWindow::MainWindow() m_ui->actionEntryCopyTitle->setShortcutVisibleInContextMenu(true); m_ui->actionEntryAddToAgent->setShortcutVisibleInContextMenu(true); m_ui->actionEntryRemoveFromAgent->setShortcutVisibleInContextMenu(true); -#endif connect(m_ui->menuEntries, SIGNAL(aboutToShow()), SLOT(obtainContextFocusLock())); connect(m_ui->menuEntries, SIGNAL(aboutToHide()), SLOT(releaseContextFocusLock())); @@ -381,19 +355,29 @@ MainWindow::MainWindow() m_ui->actionDatabaseSaveBackup->setIcon(icons()->icon("document-save-copy")); m_ui->actionDatabaseClose->setIcon(icons()->icon("document-close")); m_ui->actionReports->setIcon(icons()->icon("reports")); - m_ui->actionDatabaseSettings->setIcon(icons()->icon("document-edit")); + m_ui->actionDatabaseSettings->setIcon(icons()->icon("database-settings")); m_ui->actionDatabaseSecurity->setIcon(icons()->icon("database-change-key")); + m_ui->actionPasskeys->setIcon(icons()->icon("passkey")); + m_ui->actionImportPasskey->setIcon(icons()->icon("document-import")); m_ui->actionLockDatabase->setIcon(icons()->icon("database-lock")); m_ui->actionLockDatabaseToolbar->setIcon(icons()->icon("database-lock")); m_ui->actionLockAllDatabases->setIcon(icons()->icon("database-lock-all")); m_ui->actionQuit->setIcon(icons()->icon("application-exit")); m_ui->actionDatabaseMerge->setIcon(icons()->icon("database-merge")); + m_ui->menuRemoteSync->setIcon(icons()->icon("remote-sync")); m_ui->actionImport->setIcon(icons()->icon("document-import")); m_ui->menuExport->setIcon(icons()->icon("document-export")); +#ifndef WITH_XC_BROWSER_PASSKEYS + m_ui->actionPasskeys->setVisible(false); + m_ui->actionImportPasskey->setVisible(false); + m_ui->actionEntryImportPasskey->setVisible(false); +#endif + m_ui->actionEntryNew->setIcon(icons()->icon("entry-new")); m_ui->actionEntryClone->setIcon(icons()->icon("entry-clone")); m_ui->actionEntryEdit->setIcon(icons()->icon("entry-edit")); + m_ui->actionEntryExpire->setIcon(icons()->icon("entry-expire")); m_ui->actionEntryDelete->setIcon(icons()->icon("entry-delete")); m_ui->actionEntryRestore->setIcon(icons()->icon("entry-restore")); m_ui->actionEntryAutoType->setIcon(icons()->icon("auto-type")); @@ -415,6 +399,7 @@ MainWindow::MainWindow() m_ui->actionEntryCopyPasswordTotp->setIcon(icons()->icon("totp-copy-password")); m_ui->actionEntryTotpQRCode->setIcon(icons()->icon("qrcode")); m_ui->actionEntrySetupTotp->setIcon(icons()->icon("totp-edit")); + m_ui->actionEntryImportPasskey->setIcon(icons()->icon("document-import")); m_ui->actionEntryAddToAgent->setIcon(icons()->icon("utilities-terminal")); m_ui->actionEntryRemoveFromAgent->setIcon(icons()->icon("utilities-terminal")); m_ui->menuTags->setIcon(icons()->icon("tag-multiple")); @@ -432,6 +417,7 @@ MainWindow::MainWindow() m_ui->actionSettings->setIcon(icons()->icon("configure")); m_ui->actionPasswordGenerator->setIcon(icons()->icon("password-generator")); + m_ui->actionClearSSHAgent->setIcon(icons()->icon("utilities-terminal")); m_ui->actionAbout->setIcon(icons()->icon("help-about")); m_ui->actionDonate->setIcon(icons()->icon("donate")); @@ -446,13 +432,13 @@ MainWindow::MainWindow() m_ui->actionPasskeys->setIcon(icons()->icon("passkey")); m_ui->actionImportPasskey->setIcon(icons()->icon("document-import")); m_ui->actionEntryImportPasskey->setIcon(icons()->icon("document-import")); + m_ui->actionEntryRemovePasskey->setIcon(icons()->icon("document-close")); #endif - m_actionMultiplexer.connect( - SIGNAL(currentModeChanged(DatabaseWidget::Mode)), this, SLOT(setMenuActionState(DatabaseWidget::Mode))); - m_actionMultiplexer.connect(SIGNAL(groupChanged()), this, SLOT(setMenuActionState())); - m_actionMultiplexer.connect(SIGNAL(entrySelectionChanged()), this, SLOT(setMenuActionState())); - m_actionMultiplexer.connect(SIGNAL(databaseNonDataChanged()), this, SLOT(setMenuActionState())); + m_actionMultiplexer.connect(SIGNAL(currentModeChanged(DatabaseWidget::Mode)), this, SLOT(updateMenuActionState())); + m_actionMultiplexer.connect(SIGNAL(groupChanged()), this, SLOT(updateMenuActionState())); + m_actionMultiplexer.connect(SIGNAL(entrySelectionChanged()), this, SLOT(updateMenuActionState())); + m_actionMultiplexer.connect(SIGNAL(databaseNonDataChanged()), this, SLOT(updateMenuActionState())); m_actionMultiplexer.connect(SIGNAL(groupContextMenuRequested(QPoint)), this, SLOT(showGroupContextMenu(QPoint))); m_actionMultiplexer.connect(SIGNAL(entryContextMenuRequested(QPoint)), this, SLOT(showEntryContextMenu(QPoint))); m_actionMultiplexer.connect(SIGNAL(groupChanged()), this, SLOT(updateEntryCountLabel())); @@ -471,11 +457,11 @@ MainWindow::MainWindow() connect(m_ui->tabWidget, SIGNAL(tabNameChanged()), SLOT(updateWindowTitle())); connect(m_ui->tabWidget, SIGNAL(currentChanged(int)), SLOT(updateWindowTitle())); connect(m_ui->tabWidget, SIGNAL(currentChanged(int)), SLOT(databaseTabChanged(int))); - connect(m_ui->tabWidget, SIGNAL(currentChanged(int)), SLOT(setMenuActionState())); + connect(m_ui->tabWidget, SIGNAL(currentChanged(int)), SLOT(updateMenuActionState())); connect(m_ui->tabWidget, SIGNAL(databaseLocked(DatabaseWidget*)), SLOT(databaseStatusChanged(DatabaseWidget*))); connect(m_ui->tabWidget, SIGNAL(databaseUnlocked(DatabaseWidget*)), SLOT(databaseStatusChanged(DatabaseWidget*))); connect(m_ui->tabWidget, SIGNAL(tabVisibilityChanged(bool)), SLOT(updateToolbarSeparatorVisibility())); - connect(m_ui->stackedWidget, SIGNAL(currentChanged(int)), SLOT(setMenuActionState())); + connect(m_ui->stackedWidget, SIGNAL(currentChanged(int)), SLOT(updateMenuActionState())); connect(m_ui->stackedWidget, SIGNAL(currentChanged(int)), SLOT(updateWindowTitle())); connect(m_ui->stackedWidget, SIGNAL(currentChanged(int)), SLOT(updateToolbarSeparatorVisibility())); connect(m_ui->settingsWidget, SIGNAL(accepted()), SLOT(applySettingsChanges())); @@ -490,13 +476,14 @@ MainWindow::MainWindow() connect(m_ui->actionDatabaseSaveBackup, SIGNAL(triggered()), m_ui->tabWidget, SLOT(saveDatabaseBackup())); connect(m_ui->actionDatabaseClose, SIGNAL(triggered()), m_ui->tabWidget, SLOT(closeCurrentDatabaseTab())); connect(m_ui->actionDatabaseMerge, SIGNAL(triggered()), m_ui->tabWidget, SLOT(mergeDatabase())); + connect(m_ui->actionDatabaseSettings, SIGNAL(toggled(bool)), m_ui->tabWidget, SLOT(showDatabaseSettings(bool))); connect(m_ui->actionDatabaseSecurity, SIGNAL(triggered()), m_ui->tabWidget, SLOT(showDatabaseSecurity())); - connect(m_ui->actionReports, SIGNAL(triggered()), m_ui->tabWidget, SLOT(showDatabaseReports())); - connect(m_ui->actionDatabaseSettings, SIGNAL(triggered()), m_ui->tabWidget, SLOT(showDatabaseSettings())); + connect(m_ui->actionReports, SIGNAL(toggled(bool)), m_ui->tabWidget, SLOT(showDatabaseReports(bool))); #ifdef WITH_XC_BROWSER_PASSKEYS connect(m_ui->actionPasskeys, SIGNAL(triggered()), m_ui->tabWidget, SLOT(showPasskeys())); connect(m_ui->actionImportPasskey, SIGNAL(triggered()), m_ui->tabWidget, SLOT(importPasskey())); connect(m_ui->actionEntryImportPasskey, SIGNAL(triggered()), m_ui->tabWidget, SLOT(importPasskeyToEntry())); + connect(m_ui->actionEntryRemovePasskey, SIGNAL(triggered()), m_ui->tabWidget, SLOT(removePasskeyFromEntry())); #endif connect(m_ui->actionImport, SIGNAL(triggered()), m_ui->tabWidget, SLOT(importFile())); connect(m_ui->actionExportCsv, SIGNAL(triggered()), m_ui->tabWidget, SLOT(exportToCsv())); @@ -509,8 +496,9 @@ MainWindow::MainWindow() connect(m_ui->actionQuit, SIGNAL(triggered()), SLOT(appExit())); m_actionMultiplexer.connect(m_ui->actionEntryNew, SIGNAL(triggered()), SLOT(createEntry())); - m_actionMultiplexer.connect(m_ui->actionEntryClone, SIGNAL(triggered()), SLOT(cloneEntry())); m_actionMultiplexer.connect(m_ui->actionEntryEdit, SIGNAL(triggered()), SLOT(switchToEntryEdit())); + m_actionMultiplexer.connect(m_ui->actionEntryExpire, SIGNAL(triggered()), SLOT(expireSelectedEntries())); + m_actionMultiplexer.connect(m_ui->actionEntryClone, SIGNAL(triggered()), SLOT(cloneEntry())); m_actionMultiplexer.connect(m_ui->actionEntryDelete, SIGNAL(triggered()), SLOT(deleteSelectedEntries())); m_actionMultiplexer.connect(m_ui->actionEntryRestore, SIGNAL(triggered()), SLOT(restoreSelectedEntries())); @@ -577,14 +565,12 @@ MainWindow::MainWindow() connect(osUtils, &OSUtilsBase::statusbarThemeChanged, this, &MainWindow::updateTrayIcon); -#if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0) - // Install event filter for empty-area drag + // Install event filter for empty-area drag and menubar toggle auto* eventFilter = new MainWindowEventFilter(this); m_ui->menubar->installEventFilter(eventFilter); m_ui->toolBar->installEventFilter(eventFilter); m_ui->tabWidget->tabBar()->installEventFilter(eventFilter); installEventFilter(eventFilter); -#endif #ifdef Q_OS_MACOS setUnifiedTitleAndToolBarOnMac(true); @@ -671,15 +657,6 @@ MainWindow::MainWindow() MessageWidget::Information, -1); } -#elif (QT_VERSION >= QT_VERSION_CHECK(5, 5, 0) && QT_VERSION < QT_VERSION_CHECK(5, 6, 0)) - if (!config()->get(Config::Messages_Qt55CompatibilityWarning).toBool()) { - m_ui->globalMessageWidget->showMessage( - tr("WARNING: Your Qt version may cause KeePassXC to crash with an On-Screen Keyboard.\n" - "We recommend you use the AppImage available on our downloads page."), - MessageWidget::Warning, - -1); - config()->set(Config::Messages_Qt55CompatibilityWarning, true); - } #endif connect(qApp, SIGNAL(anotherInstanceStarted()), this, SLOT(bringToFront())); @@ -699,13 +676,17 @@ MainWindow::MainWindow() m_progressBar->setFixedHeight(15); m_progressBar->setMaximum(100); statusBar()->addPermanentWidget(m_progressBar); - connect(clipboard(), SIGNAL(updateCountdown(int, QString)), this, SLOT(updateProgressBar(int, QString))); + connect(clipboard(), &Clipboard::updateCountdown, this, &MainWindow::updateProgressBar); + m_actionMultiplexer.connect(SIGNAL(updateSyncProgress(int, QString)), this, SLOT(updateProgressBar(int, QString))); + m_actionMultiplexer.connect(SIGNAL(databaseSyncInProgress()), this, SLOT(disableMenuAndToolbar())); + m_actionMultiplexer.connect(SIGNAL(databaseSyncCompleted(QString)), this, SLOT(enableMenuAndToolbar())); + m_actionMultiplexer.connect(SIGNAL(databaseSyncFailed(QString, const QString)), this, SLOT(enableMenuAndToolbar())); m_statusBarLabel = new QLabel(statusBar()); m_statusBarLabel->setObjectName("statusBarLabel"); statusBar()->addPermanentWidget(m_statusBarLabel); restoreConfigState(); - setMenuActionState(); + updateMenuActionState(); } MainWindow::~MainWindow() @@ -756,7 +737,7 @@ void MainWindow::appExit() /** * Returns if application was built with hardware key support. - * Intented to be used by 3rd-party applications using DBus. + * Intended to be used by 3rd-party applications using DBus. * * @return True if built with hardware key support, false otherwise */ @@ -772,7 +753,7 @@ bool MainWindow::isHardwareKeySupported() /** * Refreshes list of hardware keys known. * Triggers the DatabaseOpenWidget to automatically select the key last used for a database if found. - * Intented to be used by 3rd-party applications using DBus. + * Intended to be used by 3rd-party applications using DBus. * * @return True if any key was found, false otherwise or if application lacks hardware key support */ @@ -831,31 +812,51 @@ void MainWindow::updateCopyAttributesMenu() void MainWindow::updateSetTagsMenu() { - // Remove all existing actions - m_ui->menuTags->clear(); + auto actionForTag = [](const QMenu* menu, const QString& tag) -> QAction* { + for (const auto action : menu->actions()) { + if (action->text() == tag) { + return action; + } + } + return nullptr; + }; + + m_ui->menuTags->setTearOffEnabled(true); auto dbWidget = m_ui->tabWidget->currentDatabaseWidget(); if (dbWidget) { // Enumerate tags applied to the selected entries QSet selectedTags; - for (auto entry : dbWidget->entryView()->selectedEntries()) { - for (auto tag : entry->tagList()) { + for (const auto entry : dbWidget->entryView()->selectedEntries()) { + for (const auto& tag : entry->tagList()) { selectedTags.insert(tag); } } + // Remove missing tags + const auto tagList = dbWidget->database()->tagList(); + for (const auto action : m_ui->menuTags->actions()) { + if (!tagList.contains(action->text()) || !action->isEnabled()) { + delete action; + } + } + // Add known database tags as actions and set checked if // a selected entry has that tag - for (auto tag : dbWidget->database()->tagList()) { - auto action = m_ui->menuTags->addAction(icons()->icon("tag"), tag); - action->setCheckable(true); + for (const auto& tag : tagList) { + auto action = actionForTag(m_ui->menuTags, tag); + if (!action) { + action = m_ui->menuTags->addAction(icons()->icon("tag"), tag); + action->setCheckable(true); + m_setTagsMenuActions->addAction(action); + } action->setChecked(selectedTags.contains(tag)); - m_setTagsMenuActions->addAction(action); } } // If no tags exist in the database then show a tip to the user if (m_ui->menuTags->isEmpty()) { + m_ui->menuTags->setTearOffEnabled(false); auto action = m_ui->menuTags->addAction(tr("No Tags")); action->setEnabled(false); } @@ -881,243 +882,160 @@ void MainWindow::openDatabase(const QString& filePath, const QString& password, m_ui->tabWidget->addDatabaseTab(filePath, false, password, keyfile); } -void MainWindow::setMenuActionState(DatabaseWidget::Mode mode) +void MainWindow::updateMenuActionState() { + // MainWindow State int currentIndex = m_ui->stackedWidget->currentIndex(); + bool hasLockableDatabase = m_ui->tabWidget->hasLockableDatabases(); + bool inAppSettings = (currentIndex == SettingsScreen); + bool inPasswordGenerator = (currentIndex == PasswordGeneratorScreen); - bool inDatabaseTabWidget = (currentIndex == DatabaseTabScreen); - bool inWelcomeWidget = (currentIndex == WelcomeScreen); - bool inDatabaseTabWidgetOrWelcomeWidget = inDatabaseTabWidget || inWelcomeWidget; + auto dbWidget = (currentIndex == DatabaseTabScreen ? m_ui->tabWidget->currentDatabaseWidget() : nullptr); + auto dbMode = (dbWidget ? dbWidget->currentMode() : DatabaseWidget::Mode::None); - m_ui->actionDatabaseClose->setEnabled(true); - m_ui->actionDatabaseMerge->setEnabled(inDatabaseTabWidget); - m_ui->actionDatabaseNew->setEnabled(inDatabaseTabWidgetOrWelcomeWidget); - m_ui->actionDatabaseOpen->setEnabled(inDatabaseTabWidgetOrWelcomeWidget); - m_ui->menuRecentDatabases->setEnabled(inDatabaseTabWidgetOrWelcomeWidget); - m_ui->actionImport->setEnabled(inDatabaseTabWidgetOrWelcomeWidget); - m_ui->actionLockDatabase->setEnabled(m_ui->tabWidget->hasLockableDatabases()); - m_ui->actionLockDatabaseToolbar->setEnabled(m_ui->tabWidget->hasLockableDatabases()); - m_ui->actionLockAllDatabases->setEnabled(m_ui->tabWidget->hasLockableDatabases()); + // Database State + bool databaseUnlocked = (dbWidget && !dbWidget->isLocked()); + bool inDatabase = (dbMode == DatabaseWidget::Mode::ViewMode); + bool inDatabaseSettings = (dbMode == DatabaseWidget::Mode::DatabaseSettingsMode); + bool inReports = (dbMode == DatabaseWidget::Mode::ReportsMode); + bool editingEntry = (dbMode == DatabaseWidget::Mode::EditEntryMode); - if (inDatabaseTabWidget && m_ui->tabWidget->currentIndex() != -1) { - DatabaseWidget* dbWidget = m_ui->tabWidget->currentDatabaseWidget(); - Q_ASSERT(dbWidget); + // Synchronize toggle buttons + m_ui->actionDatabaseSettings->blockSignals(true); + m_ui->actionPasswordGenerator->blockSignals(true); + m_ui->actionReports->blockSignals(true); + m_ui->actionSettings->blockSignals(true); - if (mode == DatabaseWidget::Mode::None) { - mode = dbWidget->currentMode(); + m_ui->actionDatabaseSettings->setChecked(inDatabaseSettings); + m_ui->actionPasswordGenerator->setChecked(inPasswordGenerator); + m_ui->actionReports->setChecked(inReports); + m_ui->actionSettings->setChecked(inAppSettings); + + m_ui->actionDatabaseSettings->blockSignals(false); + m_ui->actionPasswordGenerator->blockSignals(false); + m_ui->actionReports->blockSignals(false); + m_ui->actionSettings->blockSignals(false); + + // Entry State + bool singleEntrySelected = (inDatabase && dbWidget->numberOfSelectedEntries() == 1); + bool singleEntryOrEditing = (singleEntrySelected || editingEntry); + bool multiEntrySelected = (inDatabase && dbWidget->numberOfSelectedEntries() > 0); + + // Group State + bool groupSelected = (inDatabase && dbWidget->isGroupSelected()); + bool groupHasChildren = (groupSelected && dbWidget->currentGroup()->hasChildren()); + bool groupHasEntries = (groupSelected && !dbWidget->currentGroup()->entries().isEmpty()); + bool inRecycleBin = (inDatabase && dbWidget->isRecycleBinSelected()); + + bool entryViewSorted = (inDatabase && dbWidget->isSorted()); + bool entryViewAtTop = (inDatabase && dbWidget->currentEntryIndex() == 0); + bool entryViewAtBottom = + (groupSelected && dbWidget->currentEntryIndex() == dbWidget->currentGroup()->entries().size() - 1); + + m_ui->actionEntryNew->setEnabled(inDatabase && !inRecycleBin); + m_ui->actionEntryClone->setEnabled(singleEntrySelected && !inRecycleBin); + m_ui->actionEntryEdit->setEnabled(singleEntrySelected); + m_ui->actionEntryExpire->setEnabled(multiEntrySelected); + m_ui->actionEntryDelete->setEnabled(multiEntrySelected); + m_ui->actionEntryRestore->setVisible(multiEntrySelected && inRecycleBin); + m_ui->actionEntryRestore->setEnabled(multiEntrySelected && inRecycleBin); + if (dbWidget) { + m_ui->actionEntryRestore->setText(tr("Restore Entry(s)", "", dbWidget->numberOfSelectedEntries())); + m_ui->actionEntryRestore->setToolTip(tr("Restore Entry(s)", "", dbWidget->numberOfSelectedEntries())); + } + m_ui->actionEntryMoveUp->setVisible(inDatabase && !entryViewSorted); + m_ui->actionEntryMoveDown->setVisible(inDatabase && !entryViewSorted); + m_ui->actionEntryMoveUp->setEnabled(singleEntrySelected && !entryViewSorted && !entryViewAtTop); + m_ui->actionEntryMoveDown->setEnabled(singleEntrySelected && !entryViewSorted && !entryViewAtBottom); + m_ui->actionEntryCopyTitle->setEnabled(singleEntryOrEditing && dbWidget->currentEntryHasTitle()); + m_ui->actionEntryCopyUsername->setEnabled(singleEntryOrEditing && dbWidget->currentEntryHasUsername()); + // NOTE: Copy password is enabled even if the selected entry's password is blank to prevent Ctrl+C + // from copying information from the currently selected cell in the entry view table. + m_ui->actionEntryCopyPassword->setEnabled(singleEntryOrEditing); + m_ui->actionEntryCopyURL->setEnabled(singleEntryOrEditing && dbWidget->currentEntryHasUrl()); + m_ui->actionEntryCopyNotes->setEnabled(singleEntryOrEditing && dbWidget->currentEntryHasNotes()); + m_ui->menuEntryCopyAttribute->setEnabled(singleEntryOrEditing); + m_ui->menuEntryTotp->setEnabled(singleEntrySelected); + m_ui->menuTags->setEnabled(multiEntrySelected); + // Handle tear-off tags menu + if (m_ui->menuTags->isTearOffMenuVisible()) { + if (!databaseUnlocked) { + m_ui->menuTags->hideTearOffMenu(); + } else { + updateSetTagsMenu(); } - - switch (mode) { - case DatabaseWidget::Mode::ViewMode: { - bool singleEntrySelected = dbWidget->numberOfSelectedEntries() == 1; - bool entriesSelected = dbWidget->numberOfSelectedEntries() > 0; - bool groupSelected = dbWidget->isGroupSelected(); - bool currentGroupHasChildren = dbWidget->currentGroup()->hasChildren(); - bool currentGroupHasEntries = !dbWidget->currentGroup()->entries().isEmpty(); - bool recycleBinSelected = dbWidget->isRecycleBinSelected(); - bool sorted = dbWidget->isSorted(); - int entryIndex = dbWidget->currentEntryIndex(); - int numEntries = dbWidget->currentGroup()->entries().size(); - - m_ui->actionEntryNew->setEnabled(true); - m_ui->actionEntryClone->setEnabled(singleEntrySelected); - m_ui->actionEntryEdit->setEnabled(singleEntrySelected); - m_ui->actionEntryDelete->setEnabled(entriesSelected); - m_ui->actionEntryRestore->setVisible(entriesSelected && recycleBinSelected); - m_ui->actionEntryRestore->setEnabled(entriesSelected && recycleBinSelected); - m_ui->actionEntryRestore->setText(tr("Restore Entry(s)", "", dbWidget->numberOfSelectedEntries())); - m_ui->actionEntryRestore->setToolTip(tr("Restore Entry(s)", "", dbWidget->numberOfSelectedEntries())); - m_ui->actionEntryMoveUp->setVisible(!sorted); - m_ui->actionEntryMoveDown->setVisible(!sorted); - m_ui->actionEntryMoveUp->setEnabled(singleEntrySelected && !sorted && entryIndex > 0); - m_ui->actionEntryMoveDown->setEnabled(singleEntrySelected && !sorted && entryIndex >= 0 - && entryIndex < numEntries - 1); - m_ui->actionEntryCopyTitle->setEnabled(singleEntrySelected && dbWidget->currentEntryHasTitle()); - m_ui->actionEntryCopyUsername->setEnabled(singleEntrySelected && dbWidget->currentEntryHasUsername()); - // NOTE: Copy password is enabled even if the selected entry's password is blank to prevent Ctrl+C - // from copying information from the currently selected cell in the entry view table. - m_ui->actionEntryCopyPassword->setEnabled(singleEntrySelected); - m_ui->actionEntryCopyURL->setEnabled(singleEntrySelected && dbWidget->currentEntryHasUrl()); - m_ui->actionEntryCopyNotes->setEnabled(singleEntrySelected && dbWidget->currentEntryHasNotes()); - m_ui->menuEntryCopyAttribute->setEnabled(singleEntrySelected); - m_ui->menuEntryTotp->setEnabled(singleEntrySelected); - m_ui->menuTags->setEnabled(entriesSelected); - m_ui->actionEntryAutoType->setEnabled(singleEntrySelected && dbWidget->currentEntryHasAutoTypeEnabled()); - m_ui->actionEntryAutoType->menu()->setEnabled(singleEntrySelected - && dbWidget->currentEntryHasAutoTypeEnabled()); - m_ui->actionEntryAutoTypeSequence->setText( - singleEntrySelected ? dbWidget->currentSelectedEntry()->effectiveAutoTypeSequence() - : Group::RootAutoTypeSequence); - m_ui->actionEntryAutoTypeSequence->setEnabled(singleEntrySelected); - m_ui->actionEntryAutoTypeUsername->setEnabled(singleEntrySelected && dbWidget->currentEntryHasUsername()); - m_ui->actionEntryAutoTypeUsernameEnter->setEnabled(singleEntrySelected - && dbWidget->currentEntryHasUsername()); - m_ui->actionEntryAutoTypePassword->setEnabled(singleEntrySelected && dbWidget->currentEntryHasPassword()); - m_ui->actionEntryAutoTypePasswordEnter->setEnabled(singleEntrySelected - && dbWidget->currentEntryHasPassword()); - m_ui->actionEntryAutoTypeTOTP->setEnabled(singleEntrySelected && dbWidget->currentEntryHasTotp()); - m_ui->actionEntryAutoTypeTOTP->setVisible(singleEntrySelected && dbWidget->currentEntryHasTotp()); - m_ui->actionEntryOpenUrl->setEnabled(singleEntrySelected && dbWidget->currentEntryHasUrl()); - m_ui->actionEntryTotp->setEnabled(singleEntrySelected && dbWidget->currentEntryHasTotp()); - m_ui->actionEntryCopyTotp->setEnabled(singleEntrySelected && dbWidget->currentEntryHasTotp()); - m_ui->actionEntryCopyPasswordTotp->setEnabled(singleEntrySelected && dbWidget->currentEntryHasTotp()); - m_ui->actionEntrySetupTotp->setEnabled(singleEntrySelected); - m_ui->actionEntryTotpQRCode->setEnabled(singleEntrySelected && dbWidget->currentEntryHasTotp()); - m_ui->actionEntryDownloadIcon->setEnabled((entriesSelected && !singleEntrySelected) - || (singleEntrySelected && dbWidget->currentEntryHasUrl())); - m_ui->actionGroupNew->setEnabled(groupSelected); - m_ui->actionGroupEdit->setEnabled(groupSelected); - m_ui->actionGroupClone->setEnabled(groupSelected && dbWidget->canCloneCurrentGroup()); - m_ui->actionGroupDelete->setEnabled(groupSelected && dbWidget->canDeleteCurrentGroup()); - m_ui->actionGroupSortAsc->setEnabled(groupSelected && currentGroupHasChildren); - m_ui->actionGroupSortDesc->setEnabled(groupSelected && currentGroupHasChildren); - m_ui->actionGroupEmptyRecycleBin->setVisible(recycleBinSelected); - m_ui->actionGroupEmptyRecycleBin->setEnabled(recycleBinSelected); -#ifdef WITH_XC_NETWORKING - m_ui->actionGroupDownloadFavicons->setVisible(!recycleBinSelected); -#endif - m_ui->actionGroupDownloadFavicons->setEnabled(groupSelected && currentGroupHasEntries - && !recycleBinSelected); - m_ui->actionDatabaseSecurity->setEnabled(true); - m_ui->actionReports->setEnabled(true); - m_ui->actionDatabaseSettings->setEnabled(true); - m_ui->actionDatabaseSave->setEnabled(m_ui->tabWidget->canSave()); - m_ui->actionDatabaseSaveAs->setEnabled(true); - m_ui->actionDatabaseSaveBackup->setEnabled(true); - m_ui->menuExport->setEnabled(true); - m_ui->actionExportCsv->setEnabled(true); - m_ui->actionExportHtml->setEnabled(true); - m_ui->actionExportXML->setEnabled(true); - m_ui->actionDatabaseMerge->setEnabled(m_ui->tabWidget->currentIndex() != -1); + } + m_ui->actionEntryAutoType->setEnabled(singleEntrySelected && dbWidget->currentEntryHasAutoTypeEnabled()); + m_ui->actionEntryAutoType->menu()->setEnabled(singleEntrySelected && dbWidget->currentEntryHasAutoTypeEnabled()); + m_ui->actionEntryAutoTypeSequence->setText(singleEntrySelected + ? dbWidget->currentSelectedEntry()->effectiveAutoTypeSequence() + : Group::RootAutoTypeSequence); + m_ui->actionEntryAutoTypeSequence->setEnabled(singleEntrySelected); + m_ui->actionEntryAutoTypeUsername->setEnabled(singleEntrySelected && dbWidget->currentEntryHasUsername()); + m_ui->actionEntryAutoTypeUsernameEnter->setEnabled(singleEntrySelected && dbWidget->currentEntryHasUsername()); + m_ui->actionEntryAutoTypePassword->setEnabled(singleEntrySelected && dbWidget->currentEntryHasPassword()); + m_ui->actionEntryAutoTypePasswordEnter->setEnabled(singleEntrySelected && dbWidget->currentEntryHasPassword()); + m_ui->actionEntryAutoTypeTOTP->setEnabled(singleEntrySelected && dbWidget->currentEntryHasTotp()); + m_ui->actionEntryAutoTypeTOTP->setVisible(singleEntrySelected && dbWidget->currentEntryHasTotp()); + m_ui->actionEntryOpenUrl->setEnabled(singleEntryOrEditing && dbWidget->currentEntryHasUrl()); + m_ui->actionEntryTotp->setEnabled(singleEntrySelected && dbWidget->currentEntryHasTotp()); + m_ui->actionEntryCopyTotp->setEnabled(singleEntrySelected && dbWidget->currentEntryHasTotp()); + m_ui->actionEntryCopyPasswordTotp->setEnabled(singleEntrySelected && dbWidget->currentEntryHasTotp()); + m_ui->actionEntrySetupTotp->setEnabled(singleEntrySelected); + m_ui->actionEntryTotpQRCode->setEnabled(singleEntrySelected && dbWidget->currentEntryHasTotp()); + m_ui->actionEntryDownloadIcon->setEnabled((multiEntrySelected && !singleEntrySelected) + || (singleEntrySelected && dbWidget->currentEntryHasUrl())); #ifdef WITH_XC_BROWSER_PASSKEYS - m_ui->actionPasskeys->setEnabled(true); - m_ui->actionImportPasskey->setEnabled(true); - m_ui->actionEntryImportPasskey->setEnabled(singleEntrySelected); + m_ui->actionEntryImportPasskey->setVisible(singleEntrySelected); + m_ui->actionEntryImportPasskey->setEnabled(singleEntrySelected); + m_ui->actionEntryRemovePasskey->setVisible(singleEntrySelected && dbWidget->currentEntryHasPasskey()); + m_ui->actionEntryRemovePasskey->setEnabled(singleEntrySelected && dbWidget->currentEntryHasPasskey()); #endif #ifdef WITH_XC_SSHAGENT - bool singleEntryHasSshKey = - singleEntrySelected && sshAgent()->isEnabled() && dbWidget->currentEntryHasSshKey(); - m_ui->actionEntryAddToAgent->setVisible(singleEntryHasSshKey); - m_ui->actionEntryAddToAgent->setEnabled(singleEntryHasSshKey); - m_ui->actionEntryRemoveFromAgent->setVisible(singleEntryHasSshKey); - m_ui->actionEntryRemoveFromAgent->setEnabled(singleEntryHasSshKey); + bool hasSSHKey = singleEntrySelected && sshAgent()->isEnabled() && dbWidget->currentEntryHasSshKey(); + m_ui->actionEntryAddToAgent->setVisible(hasSSHKey); + m_ui->actionEntryAddToAgent->setEnabled(hasSSHKey); + m_ui->actionEntryRemoveFromAgent->setVisible(hasSSHKey); + m_ui->actionEntryRemoveFromAgent->setEnabled(hasSSHKey); + m_ui->actionClearSSHAgent->setVisible(sshAgent()->isEnabled()); + m_ui->actionClearSSHAgent->setEnabled(sshAgent()->isEnabled()); #endif - m_searchWidgetAction->setEnabled(true); - - break; - } - case DatabaseWidget::Mode::EditMode: - case DatabaseWidget::Mode::LockedMode: { - // Enable select actions when editing an entry - bool editEntryActive = dbWidget->isEntryEditActive(); - const auto editEntryActionsMask = QList({m_ui->actionEntryCopyUsername, - m_ui->actionEntryCopyPassword, - m_ui->actionEntryCopyURL, - m_ui->actionEntryOpenUrl, - m_ui->actionEntryAutoType, - m_ui->actionEntryDownloadIcon, - m_ui->actionEntryCopyNotes, - m_ui->actionEntryCopyTitle, - m_ui->menuEntryCopyAttribute->menuAction(), - m_ui->menuEntryTotp->menuAction(), - m_ui->actionEntrySetupTotp}); - - auto entryActions = m_ui->menuEntries->actions(); - entryActions << m_ui->menuEntryCopyAttribute->actions(); - entryActions << m_ui->menuEntryTotp->actions(); - for (auto action : entryActions) { - bool enabled = editEntryActive && editEntryActionsMask.contains(action); - if (action->menu()) { - action->menu()->setEnabled(enabled); - } - action->setEnabled(enabled); - } - - const auto groupActions = m_ui->menuGroups->actions(); - for (auto action : groupActions) { - action->setEnabled(false); - } - - m_ui->actionDatabaseSecurity->setEnabled(false); - m_ui->actionReports->setEnabled(false); - m_ui->actionDatabaseSettings->setEnabled(false); - m_ui->actionDatabaseSave->setEnabled(false); - m_ui->actionDatabaseSaveAs->setEnabled(false); - m_ui->actionDatabaseSaveBackup->setEnabled(false); - m_ui->menuExport->setEnabled(false); - m_ui->actionExportCsv->setEnabled(false); - m_ui->actionExportHtml->setEnabled(false); - m_ui->actionDatabaseMerge->setEnabled(false); - // Only disable the action in the database menu so that the - // menu remains active in the toolbar, if necessary - m_ui->actionLockDatabase->setEnabled(false); - // Never show in these modes - m_ui->actionEntryMoveUp->setVisible(false); - m_ui->actionEntryMoveDown->setVisible(false); - m_ui->actionEntryRestore->setVisible(false); - m_ui->actionEntryAddToAgent->setVisible(false); - m_ui->actionEntryRemoveFromAgent->setVisible(false); - m_ui->actionGroupEmptyRecycleBin->setVisible(false); + m_ui->actionGroupNew->setEnabled(groupSelected && !inRecycleBin); + m_ui->actionGroupEdit->setEnabled(groupSelected); + m_ui->actionGroupClone->setEnabled(groupSelected && dbWidget->canCloneCurrentGroup()); + m_ui->actionGroupDelete->setEnabled(groupSelected && dbWidget->canDeleteCurrentGroup()); + m_ui->actionGroupSortAsc->setVisible(groupHasChildren); + m_ui->actionGroupSortAsc->setEnabled(groupHasChildren); + m_ui->actionGroupSortDesc->setVisible(groupHasChildren); + m_ui->actionGroupSortDesc->setEnabled(groupHasChildren); + m_ui->actionGroupEmptyRecycleBin->setVisible(inRecycleBin); + m_ui->actionGroupEmptyRecycleBin->setEnabled(inRecycleBin); +#ifdef WITH_XC_NETWORKING + m_ui->actionGroupDownloadFavicons->setVisible(!inRecycleBin); +#endif + m_ui->actionGroupDownloadFavicons->setEnabled(groupSelected && groupHasEntries && !inRecycleBin); + // Database Menu + m_ui->actionDatabaseSave->setEnabled(databaseUnlocked && m_ui->tabWidget->canSave()); + m_ui->actionDatabaseSaveAs->setEnabled(databaseUnlocked); + m_ui->actionDatabaseSaveBackup->setEnabled(databaseUnlocked); + m_ui->actionDatabaseClose->setEnabled(dbWidget); + m_ui->actionLockDatabase->setEnabled(databaseUnlocked); + m_ui->actionLockAllDatabases->setEnabled(hasLockableDatabase); + m_ui->actionLockDatabaseToolbar->setEnabled(hasLockableDatabase); + m_ui->actionDatabaseSettings->setEnabled(inDatabase || inDatabaseSettings); + m_ui->actionDatabaseSecurity->setEnabled(inDatabase || inDatabaseSettings); + m_ui->actionReports->setEnabled(inDatabase || inReports); + m_ui->menuRemoteSync->setEnabled(inDatabase || inDatabaseSettings); + m_ui->menuExport->setEnabled(inDatabase); + m_ui->actionDatabaseMerge->setEnabled(inDatabase); #ifdef WITH_XC_BROWSER_PASSKEYS - m_ui->actionPasskeys->setEnabled(false); - m_ui->actionImportPasskey->setEnabled(false); - m_ui->actionEntryImportPasskey->setEnabled(false); -#else - m_ui->actionPasskeys->setVisible(false); - m_ui->actionImportPasskey->setVisible(false); - m_ui->actionEntryImportPasskey->setVisible(false); + m_ui->actionPasskeys->setEnabled(inDatabase || inReports); + m_ui->actionImportPasskey->setEnabled(inDatabase); #endif - m_searchWidgetAction->setEnabled(false); - break; - } - default: - Q_ASSERT(false); - } - } else { - const auto entryActions = m_ui->menuEntries->actions(); - for (auto action : entryActions) { - action->setEnabled(false); - } - - const auto groupActions = m_ui->menuGroups->actions(); - for (auto action : groupActions) { - action->setEnabled(false); - } - - m_ui->actionDatabaseSecurity->setEnabled(false); - m_ui->actionReports->setEnabled(false); - m_ui->actionDatabaseSettings->setEnabled(false); - m_ui->actionDatabaseSave->setEnabled(false); - m_ui->actionDatabaseSaveAs->setEnabled(false); - m_ui->actionDatabaseSaveBackup->setEnabled(false); - m_ui->actionDatabaseClose->setEnabled(false); - m_ui->menuExport->setEnabled(false); - m_ui->actionExportCsv->setEnabled(false); - m_ui->actionExportHtml->setEnabled(false); - m_ui->actionDatabaseMerge->setEnabled(false); - // Hide entry-specific actions - m_ui->actionEntryMoveUp->setVisible(false); - m_ui->actionEntryMoveDown->setVisible(false); - m_ui->actionEntryRestore->setVisible(false); - m_ui->actionEntryAddToAgent->setVisible(false); - m_ui->actionEntryRemoveFromAgent->setVisible(false); - m_ui->actionGroupEmptyRecycleBin->setVisible(false); - - m_searchWidgetAction->setEnabled(false); - } - - if ((currentIndex == PasswordGeneratorScreen) != m_ui->actionPasswordGenerator->isChecked()) { - bool blocked = m_ui->actionPasswordGenerator->blockSignals(true); - m_ui->actionPasswordGenerator->toggle(); - m_ui->actionPasswordGenerator->blockSignals(blocked); - } else if ((currentIndex == SettingsScreen) != m_ui->actionSettings->isChecked()) { - bool blocked = m_ui->actionSettings->blockSignals(true); - m_ui->actionSettings->toggle(); - m_ui->actionSettings->blockSignals(blocked); - } + m_searchWidgetAction->setEnabled(inDatabase); } void MainWindow::updateToolbarSeparatorVisibility() @@ -1149,28 +1067,23 @@ void MainWindow::updateWindowTitle() if (stackedWidgetIndex == DatabaseTabScreen && tabWidgetIndex != -1) { customWindowTitlePart = m_ui->tabWidget->tabName(tabWidgetIndex); - if (isModified) { - // remove asterisk '*' from title + if (isModified && customWindowTitlePart.endsWith("*")) { customWindowTitlePart.remove(customWindowTitlePart.size() - 1, 1); } m_ui->actionDatabaseSave->setEnabled(m_ui->tabWidget->canSave(tabWidgetIndex)); - } else if (stackedWidgetIndex == 1) { + } else if (stackedWidgetIndex == StackedWidgetIndex::SettingsScreen) { customWindowTitlePart = tr("Settings"); + } else if (stackedWidgetIndex == StackedWidgetIndex::PasswordGeneratorScreen) { + customWindowTitlePart = tr("Password Generator"); } QString windowTitle; if (customWindowTitlePart.isEmpty()) { - windowTitle = BaseWindowTitle; + windowTitle = QString("%1[*]").arg(BaseWindowTitle); } else { windowTitle = QString("%1[*] - %2").arg(customWindowTitlePart, BaseWindowTitle); } - if (customWindowTitlePart.isEmpty() || stackedWidgetIndex == 1) { - setWindowFilePath(""); - } else { - setWindowFilePath(m_ui->tabWidget->databaseWidgetFromIndex(tabWidgetIndex)->database()->filePath()); - } - setWindowTitle(windowTitle); setWindowModified(isModified); @@ -1280,8 +1193,10 @@ void MainWindow::switchToDatabases() { if (m_ui->tabWidget->currentIndex() == -1) { m_ui->stackedWidget->setCurrentIndex(WelcomeScreen); + statusBar()->setAutoFillBackground(false); } else { m_ui->stackedWidget->setCurrentIndex(DatabaseTabScreen); + statusBar()->setAutoFillBackground(true); } } @@ -1290,6 +1205,7 @@ void MainWindow::switchToSettings(bool enabled) if (enabled) { m_ui->settingsWidget->loadSettings(); m_ui->stackedWidget->setCurrentIndex(SettingsScreen); + statusBar()->setAutoFillBackground(true); } else { switchToDatabases(); } @@ -1301,6 +1217,7 @@ void MainWindow::togglePasswordGenerator(bool enabled) m_ui->passwordGeneratorWidget->loadSettings(); m_ui->passwordGeneratorWidget->regeneratePassword(); m_ui->stackedWidget->setCurrentIndex(PasswordGeneratorScreen); + statusBar()->setAutoFillBackground(false); } else { m_ui->passwordGeneratorWidget->saveSettings(); switchToDatabases(); @@ -1325,6 +1242,27 @@ void MainWindow::switchToDatabaseFile(const QString& file) switchToDatabases(); } +void MainWindow::updateRemoteSyncMenuEntries() +{ + m_ui->menuRemoteSync->clear(); + + auto dbWidget = m_ui->tabWidget->currentDatabaseWidget(); + if (dbWidget) { + // Setup sync shortcut + auto action = m_ui->menuRemoteSync->addAction(tr("Setup Remote Sync…")); + connect(action, &QAction::triggered, dbWidget, &DatabaseWidget::switchToRemoteSettings); + + m_ui->menuRemoteSync->addSeparator(); + + // Build remote sync menu + for (const auto params : dbWidget->getRemoteParams()) { + auto* remoteSyncAction = new QAction(params->name, this); + m_ui->menuRemoteSync->addAction(remoteSyncAction); + connect(remoteSyncAction, &QAction::triggered, dbWidget, [=] { dbWidget->syncWithRemote(params); }); + } + } +} + void MainWindow::databaseStatusChanged(DatabaseWidget* dbWidget) { Q_UNUSED(dbWidget); @@ -1369,12 +1307,46 @@ void MainWindow::databaseTabChanged(int tabIndex) { if (tabIndex != -1 && m_ui->stackedWidget->currentIndex() == WelcomeScreen) { m_ui->stackedWidget->setCurrentIndex(DatabaseTabScreen); + statusBar()->setAutoFillBackground(true); } else if (tabIndex == -1 && m_ui->stackedWidget->currentIndex() == DatabaseTabScreen) { m_ui->stackedWidget->setCurrentIndex(WelcomeScreen); + statusBar()->setAutoFillBackground(false); } m_actionMultiplexer.setCurrentObject(m_ui->tabWidget->currentDatabaseWidget()); updateEntryCountLabel(); + + // Clear the tags menu to prevent re-use between databases + for (const auto action : m_ui->menuTags->actions()) { + delete action; + } +} + +bool MainWindow::event(QEvent* event) +{ + if (event->type() == QEvent::ShortcutOverride) { + const auto keyevent = static_cast(event); + // Did we get a ShortcutOverride event with the same key sequence as the OS default + // copy-to-clipboard shortcut? + if (keyevent->matches(QKeySequence::Copy)) { + // If so, we ask the database widget to check if any of its sub-widgets has + // text selected, and to copy it to the clipboard if that is the case. + // We do this because that is what the user likely expects to happen, yet Qt does not + // behave like that (at least on some platforms). + auto dbWidget = m_ui->tabWidget->currentDatabaseWidget(); + if (dbWidget && dbWidget->copyFocusedTextSelection()) { + // Note: instead of actively copying the selected text to the clipboard + // above, simply accepting the event would have a similar effect (Qt + // would deliver it as a key press to the current widget, which would + // trigger the built-in copy-to-clipboard behaviour). However, that + // would not come with our special (configurable) behaviour of + // clearing the clipboard after a certain time period. + keyevent->accept(); + return true; + } + } + } + return QMainWindow::event(event); } void MainWindow::showEvent(QShowEvent* event) @@ -1462,7 +1434,7 @@ void MainWindow::keyPressEvent(QKeyEvent* event) } } - QWidget::keyPressEvent(event); + QMainWindow::keyPressEvent(event); } bool MainWindow::focusNextPrevChild(bool next) @@ -1512,6 +1484,27 @@ void MainWindow::focusSearchWidget() } } +void MainWindow::enableMenuAndToolbar() +{ + m_ui->toolBar->setDisabled(false); + m_ui->menubar->setDisabled(false); +} + +void MainWindow::disableMenuAndToolbar() +{ + m_ui->toolBar->setDisabled(true); + m_ui->menubar->setDisabled(true); +} + +void MainWindow::clearSSHAgent() +{ +#ifdef WITH_XC_SSHAGENT + auto agent = SSHAgent::instance(); + auto ret = agent->clearAllAgentIdentities(); + displayGlobalMessage(agent->errorString(), ret ? MessageWidget::Positive : KMessageWidget::Error, false); +#endif +} + void MainWindow::saveWindowInformation() { if (isVisible()) { @@ -1524,7 +1517,7 @@ bool MainWindow::saveLastDatabases() { if (config()->get(Config::OpenPreviousDatabasesOnStartup).toBool()) { auto currentDbWidget = m_ui->tabWidget->currentDatabaseWidget(); - if (currentDbWidget) { + if (currentDbWidget && !currentDbWidget->database()->isTemporaryDatabase()) { config()->set(Config::LastActiveDatabase, currentDbWidget->database()->filePath()); } else { config()->remove(Config::LastActiveDatabase); @@ -1533,7 +1526,9 @@ bool MainWindow::saveLastDatabases() QStringList openDatabases; for (int i = 0; i < m_ui->tabWidget->count(); ++i) { auto dbWidget = m_ui->tabWidget->databaseWidgetFromIndex(i); - openDatabases.append(QDir::toNativeSeparators(dbWidget->database()->filePath())); + if (!dbWidget->database()->isTemporaryDatabase()) { + openDatabases.append(QDir::toNativeSeparators(dbWidget->database()->filePath())); + } } config()->set(Config::LastOpenedDatabases, openDatabases); @@ -1635,6 +1630,8 @@ void MainWindow::agentEnabled(bool enabled) { m_ui->actionEntryAddToAgent->setVisible(enabled); m_ui->actionEntryRemoveFromAgent->setVisible(enabled); + m_ui->actionClearSSHAgent->setEnabled(enabled); + m_ui->actionClearSSHAgent->setVisible(enabled); } void MainWindow::showEntryContextMenu(const QPoint& globalPos) @@ -1657,29 +1654,17 @@ void MainWindow::showGroupContextMenu(const QPoint& globalPos) m_ui->menuGroups->popup(globalPos); } -void MainWindow::setShortcut(QAction* action, QKeySequence::StandardKey standard, int fallback) -{ - if (!QKeySequence::keyBindings(standard).isEmpty()) { - action->setShortcuts(standard); - } else if (fallback != 0) { - action->setShortcut(QKeySequence(fallback)); - } -} - void MainWindow::applySettingsChanges() { - int timeout = config()->get(Config::Security_LockDatabaseIdleSeconds).toInt() * 1000; - if (timeout <= 0) { - timeout = 60; - } - - m_inactivityTimer->setInactivityTimeout(timeout); if (config()->get(Config::Security_LockDatabaseIdle).toBool()) { - m_inactivityTimer->activate(); + auto timeout = config()->get(Config::Security_LockDatabaseIdleSeconds).toInt() * 1000; + m_inactivityTimer->activate(timeout); } else { m_inactivityTimer->deactivate(); } + m_ui->actionShowToolbar->setChecked(!config()->get(Config::GUI_HideToolbar).toBool()); + m_ui->actionShowMenubar->setChecked(!config()->get(Config::GUI_HideMenubar).toBool()); m_ui->menubar->setHidden(config()->get(Config::GUI_HideMenubar).toBool()); m_ui->toolBar->setHidden(config()->get(Config::GUI_HideToolbar).toBool()); auto movable = config()->get(Config::GUI_MovableToolbar).toBool(); @@ -1697,6 +1682,8 @@ void MainWindow::applySettingsChanges() } updateTrayIcon(); + + kpxcApp->applyFontSize(); } void MainWindow::setAllowScreenCapture(bool state) @@ -1785,7 +1772,7 @@ void MainWindow::hide() { #ifndef Q_OS_WIN qint64 current_time = Clock::currentMilliSecondsSinceEpoch(); - if (current_time - m_lastShowTime < 50) { + if (current_time - m_lastShowTime < 250) { return; } #endif @@ -1831,27 +1818,6 @@ void MainWindow::toggleWindow() hideWindow(); } else { bringToFront(); - -#if defined(Q_OS_UNIX) && !defined(Q_OS_MACOS) && !defined(QT_NO_DBUS) && (QT_VERSION < QT_VERSION_CHECK(5, 9, 0)) - // re-register global D-Bus menu (needed on Ubuntu with Unity) - // see https://github.com/keepassxreboot/keepassxc/issues/271 - // and https://bugreports.qt.io/browse/QTBUG-58723 - // check for !isVisible(), because isNativeMenuBar() does not work with appmenu-qt5 - static const auto isDesktopSessionUnity = qgetenv("XDG_CURRENT_DESKTOP") == "Unity"; - - if (isDesktopSessionUnity && Tools::qtRuntimeVersion() < QT_VERSION_CHECK(5, 9, 0) - && !m_ui->menubar->isVisible()) { - QDBusMessage msg = QDBusMessage::createMethodCall(QStringLiteral("com.canonical.AppMenu.Registrar"), - QStringLiteral("/com/canonical/AppMenu/Registrar"), - QStringLiteral("com.canonical.AppMenu.Registrar"), - QStringLiteral("RegisterWindow")); - QList args; - args << QVariant::fromValue(static_cast(winId())) - << QVariant::fromValue(QDBusObjectPath("/MenuBar/1")); - msg.setArguments(args); - QDBusConnection::sessionBus().send(msg); - } -#endif } } @@ -1862,13 +1828,6 @@ void MainWindow::closeModalWindow() } } -void MainWindow::lockDatabasesAfterInactivity() -{ - if (!m_ui->tabWidget->lockDatabases()) { - m_inactivityTimer->activate(); - } -} - bool MainWindow::isTrayIconEnabled() const { return m_trayIcon && m_trayIcon->isVisible(); @@ -1923,7 +1882,7 @@ void MainWindow::bringToFront() void MainWindow::handleScreenLock() { if (config()->get(Config::Security_LockDatabaseScreenLock).toBool()) { - lockDatabasesAfterInactivity(); + lockAllDatabases(); } } @@ -1973,7 +1932,7 @@ void MainWindow::closeAllDatabases() void MainWindow::lockAllDatabases() { - lockDatabasesAfterInactivity(); + m_ui->tabWidget->lockDatabases(); } void MainWindow::displayDesktopNotification(const QString& msg, QString title, int msTimeoutHint) @@ -1986,11 +1945,7 @@ void MainWindow::displayDesktopNotification(const QString& msg, QString title, i title = BaseWindowTitle; } -#if QT_VERSION >= QT_VERSION_CHECK(5, 9, 0) m_trayIcon->showMessage(title, msg, icons()->applicationIcon(), msTimeoutHint); -#else - m_trayIcon->showMessage(title, msg, QSystemTrayIcon::Information, msTimeoutHint); -#endif } void MainWindow::restartApp(const QString& message) @@ -2061,6 +2016,11 @@ void MainWindow::initViewMenu() applySettingsChanges(); }); + m_ui->actionShowGroupPanel->setChecked(!config()->get(Config::GUI_HideGroupPanel).toBool()); + connect(m_ui->actionShowGroupPanel, &QAction::toggled, this, [](bool checked) { + config()->set(Config::GUI_HideGroupPanel, !checked); + }); + m_ui->actionShowPreviewPanel->setChecked(!config()->get(Config::GUI_HidePreviewPanel).toBool()); connect(m_ui->actionShowPreviewPanel, &QAction::toggled, this, [](bool checked) { config()->set(Config::GUI_HidePreviewPanel, !checked); @@ -2089,11 +2049,148 @@ void MainWindow::initViewMenu() }); } -#if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0) +void MainWindow::initActionCollection() +{ + auto ac = ActionCollection::instance(); + ac->addActions({// Database Menu + m_ui->actionDatabaseNew, + m_ui->actionDatabaseOpen, + m_ui->actionDatabaseSave, + m_ui->actionDatabaseSaveAs, + m_ui->actionDatabaseSaveBackup, + m_ui->actionDatabaseClose, + m_ui->actionLockDatabase, + m_ui->actionLockAllDatabases, + m_ui->actionDatabaseSettings, + m_ui->actionDatabaseSecurity, + m_ui->actionReports, + m_ui->actionPasskeys, + m_ui->actionDatabaseMerge, + m_ui->actionImportPasskey, + m_ui->actionImportCsv, + m_ui->actionImportOpVault, + m_ui->actionImportKeePass1, + m_ui->actionExportCsv, + m_ui->actionExportHtml, + m_ui->actionExportXML, + m_ui->actionQuit, + // Entry Menu + m_ui->actionEntryNew, + m_ui->actionEntryEdit, + m_ui->actionEntryClone, + m_ui->actionEntryDelete, + m_ui->actionEntryCopyUsername, + m_ui->actionEntryCopyPassword, + m_ui->actionEntryCopyURL, + m_ui->actionEntryCopyTitle, + m_ui->actionEntryCopyNotes, + m_ui->actionEntryTotp, + m_ui->actionEntryTotpQRCode, + m_ui->actionEntrySetupTotp, + m_ui->actionEntryCopyTotp, + m_ui->actionEntryCopyPasswordTotp, + m_ui->actionEntryAutoTypeSequence, + m_ui->actionEntryAutoTypeUsername, + m_ui->actionEntryAutoTypeUsernameEnter, + m_ui->actionEntryAutoTypePassword, + m_ui->actionEntryAutoTypePasswordEnter, + m_ui->actionEntryAutoTypeTOTP, + m_ui->actionEntryDownloadIcon, + m_ui->actionEntryOpenUrl, + m_ui->actionEntryMoveUp, + m_ui->actionEntryMoveDown, + m_ui->actionEntryAddToAgent, + m_ui->actionEntryRemoveFromAgent, + m_ui->actionEntryRestore, + // Group Menu + m_ui->actionGroupNew, + m_ui->actionGroupEdit, + m_ui->actionGroupClone, + m_ui->actionGroupDelete, + m_ui->actionGroupDownloadFavicons, + m_ui->actionGroupSortAsc, + m_ui->actionGroupSortDesc, + m_ui->actionGroupEmptyRecycleBin, + // Tools Menu + m_ui->actionPasswordGenerator, + m_ui->actionClearSSHAgent, + m_ui->actionSettings, + // View Menu + m_ui->actionThemeAuto, + m_ui->actionThemeLight, + m_ui->actionThemeDark, + m_ui->actionThemeClassic, + m_ui->actionCompactMode, +#ifndef Q_OS_MACOS + m_ui->actionShowMenubar, +#endif + m_ui->actionShowToolbar, + m_ui->actionShowGroupPanel, + m_ui->actionShowPreviewPanel, + m_ui->actionAllowScreenCapture, + m_ui->actionAlwaysOnTop, + m_ui->actionHideUsernames, + m_ui->actionHidePasswords, + // Help Menu + m_ui->actionGettingStarted, + m_ui->actionUserGuide, + m_ui->actionKeyboardShortcuts, + m_ui->actionOnlineHelp, + m_ui->actionCheckForUpdates, + m_ui->actionDonate, + m_ui->actionBugReport, + m_ui->actionAbout}); + + // Register as default any shortcuts that were set in the .ui file + for (const auto action : ac->actions()) { + if (!action->shortcut().isEmpty()) { + ac->setDefaultShortcut(action, action->shortcut()); + } + } + + // Actions with standard shortcuts (if no standard shortcut exists, leave the existing + // shortcuts from the .ui file in place) + ac->setDefaultShortcut(m_ui->actionDatabaseOpen, QKeySequence::Open); + ac->setDefaultShortcut(m_ui->actionDatabaseSave, QKeySequence::Save); + ac->setDefaultShortcut(m_ui->actionDatabaseSaveAs, QKeySequence::SaveAs); + ac->setDefaultShortcut(m_ui->actionDatabaseClose, QKeySequence::Close); + ac->setDefaultShortcut(m_ui->actionSettings, QKeySequence::Preferences); + ac->setDefaultShortcut(m_ui->actionQuit, QKeySequence::Quit); + ac->setDefaultShortcut(m_ui->actionEntryNew, QKeySequence::New); + + // Prevent conflicts with global Mac shortcuts (force Control on all platforms) + // Note: Qt::META means Ctrl on Mac. +#ifdef Q_OS_MAC + ac->setDefaultShortcut(m_ui->actionEntryAddToAgent, Qt::META + Qt::Key_H); + ac->setDefaultShortcut(m_ui->actionEntryRemoveFromAgent, Qt::META + Qt::SHIFT + Qt::Key_H); +#endif + + QTimer::singleShot(1, ac, &ActionCollection::restoreShortcuts); +} MainWindowEventFilter::MainWindowEventFilter(QObject* parent) : QObject(parent) { + m_altCoolDown.setInterval(250); + m_altCoolDown.setSingleShot(true); + + m_menubarTimer.setInterval(250); + m_menubarTimer.setSingleShot(false); + connect(&m_menubarTimer, &QTimer::timeout, this, [this] { + auto mainwindow = getMainWindow(); + if (mainwindow && mainwindow->m_ui->menubar->isVisible() && config()->get(Config::GUI_HideMenubar).toBool()) { + // If the menu bar is visible with no active menu, hide it + if (!mainwindow->m_ui->menubar->activeAction()) { + mainwindow->m_ui->menubar->setVisible(false); + m_altCoolDown.start(); + m_menubarTimer.stop(); + } + // Conditions to hide the menubar or stop the timer have not been met + return; + } + // We no longer need the timer + m_menubarTimer.stop(); + }); } /** @@ -2109,6 +2206,8 @@ bool MainWindowEventFilter::eventFilter(QObject* watched, QEvent* event) auto eventType = event->type(); if (eventType == QEvent::MouseButtonPress) { +#if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0) + // startSystemMove was introduced in Qt 5.15 auto mouseEvent = dynamic_cast(event); if (watched == mainWindow->m_ui->menubar) { if (!mainWindow->m_ui->menubar->actionAt(mouseEvent->pos())) { @@ -2126,22 +2225,31 @@ bool MainWindowEventFilter::eventFilter(QObject* watched, QEvent* event) return true; } } - } else if (eventType == QEvent::KeyRelease) { - if (watched == mainWindow) { - auto keyEvent = dynamic_cast(event); - if (keyEvent->key() == Qt::Key_Alt && !keyEvent->modifiers() - && config()->get(Config::GUI_HideMenubar).toBool()) { - auto menubar = mainWindow->m_ui->menubar; - menubar->setVisible(!menubar->isVisible()); - if (menubar->isVisible()) { - menubar->setActiveAction(mainWindow->m_ui->menuFile->menuAction()); - } - return false; +#endif + } else if (eventType == QEvent::KeyRelease && watched == mainWindow) { + auto keyEvent = dynamic_cast(event); +#ifdef Q_OS_WIN + // Windows translates AltGr into CTRL + ALT, this breaks using AltGr when the menubar is hidden + // Prevent this by activating the ALT cooldown to ignore the next key event which will be an ALT key + if (keyEvent->key() == Qt::Key_Control && keyEvent->modifiers() == Qt::AltModifier + && config()->get(Config::GUI_HideMenubar).toBool()) { + m_altCoolDown.start(); + return false; + } +#endif + if (keyEvent->key() == Qt::Key_Alt && !keyEvent->modifiers() && config()->get(Config::GUI_HideMenubar).toBool() + && !m_altCoolDown.isActive()) { + auto menubar = mainWindow->m_ui->menubar; + menubar->setVisible(!menubar->isVisible()); + if (menubar->isVisible()) { + menubar->setActiveAction(mainWindow->m_ui->menuFile->menuAction()); + m_menubarTimer.start(); + } else { + m_menubarTimer.stop(); } + return true; } } return QObject::eventFilter(watched, event); } - -#endif diff --git a/src/gui/MainWindow.h b/src/gui/MainWindow.h index 1f96a6ec0..229106c52 100644 --- a/src/gui/MainWindow.h +++ b/src/gui/MainWindow.h @@ -1,6 +1,6 @@ /* + * Copyright (C) 2024 KeePassXC Team * Copyright (C) 2010 Felix Geyer - * Copyright (C) 2020 KeePassXC Team * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -49,7 +49,7 @@ class MainWindow : public QMainWindow public: MainWindow(); - ~MainWindow(); + ~MainWindow() override; QList getOpenDatabases(); void restoreConfigState(); @@ -67,6 +67,7 @@ signals: void databaseUnlocked(DatabaseWidget* dbWidget); void databaseLocked(DatabaseWidget* dbWidget); void activeDatabaseChanged(DatabaseWidget* dbWidget); + void databaseUnlockDialogFinished(bool accepted, DatabaseWidget* dbWidget); public slots: void openDatabase(const QString& filePath, const QString& password = {}, const QString& keyfile = {}); @@ -97,6 +98,7 @@ public slots: void restartApp(const QString& message); protected: + bool event(QEvent* event) override; void showEvent(QShowEvent* event) override; void hideEvent(QHideEvent* event) override; void closeEvent(QCloseEvent* event) override; @@ -105,7 +107,7 @@ protected: bool focusNextPrevChild(bool next) override; private slots: - void setMenuActionState(DatabaseWidget::Mode mode = DatabaseWidget::Mode::None); + void updateMenuActionState(); void updateToolbarSeparatorVisibility(); void updateWindowTitle(); void showAboutDialog(); @@ -125,6 +127,7 @@ private slots: void switchToNewDatabase(); void switchToOpenDatabase(); void switchToDatabaseFile(const QString& file); + void updateRemoteSyncMenuEntries(); void databaseStatusChanged(DatabaseWidget* dbWidget); void databaseTabChanged(int tabIndex); void openRecentDatabase(QAction* action); @@ -137,7 +140,6 @@ private slots: void applySettingsChanges(); void trayIconTriggered(QSystemTrayIcon::ActivationReason reason); void processTrayIconTrigger(); - void lockDatabasesAfterInactivity(); void handleScreenLock(); void showErrorMessage(const QString& message); void selectNextDatabaseTab(); @@ -150,10 +152,11 @@ private slots: void updateProgressBar(int percentage, QString message); void updateEntryCountLabel(); void focusSearchWidget(); + void enableMenuAndToolbar(); + void disableMenuAndToolbar(); + void clearSSHAgent(); private: - static void setShortcut(QAction* action, QKeySequence::StandardKey standard, int fallback = 0); - static const QString BaseWindowTitle; void saveWindowInformation(); @@ -166,6 +169,7 @@ private: void dropEvent(QDropEvent* event) override; void initViewMenu(); + void initActionCollection(); const QScopedPointer m_ui; SignalMultiplexer m_actionMultiplexer; @@ -203,7 +207,6 @@ private: friend class MainWindowEventFilter; }; -#if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0) class MainWindowEventFilter : public QObject { Q_OBJECT @@ -211,8 +214,11 @@ class MainWindowEventFilter : public QObject public: explicit MainWindowEventFilter(QObject* parent); bool eventFilter(QObject* watched, QEvent* event) override; + +private: + QTimer m_menubarTimer; + QTimer m_altCoolDown; }; -#endif /** * Return instance of MainWindow created on app load diff --git a/src/gui/MainWindow.ui b/src/gui/MainWindow.ui index a1dc25c58..283bfd999 100644 --- a/src/gui/MainWindow.ui +++ b/src/gui/MainWindow.ui @@ -239,6 +239,12 @@ + + + Remote S&ync… + + + @@ -250,14 +256,15 @@ - + + @@ -286,9 +293,6 @@ true - - false - @@ -300,9 +304,6 @@ - - false - TOTP @@ -313,12 +314,17 @@ + + true + Tags + + @@ -335,6 +341,7 @@ + @@ -348,22 +355,24 @@ &Groups + + - - - + + &Tools + @@ -383,9 +392,13 @@ + + + + @@ -428,6 +441,9 @@ + + + @@ -436,6 +452,12 @@ &Quit + + Quit Application + + + Ctrl+Q + QAction::QuitRole @@ -444,6 +466,9 @@ &About + + Open About Dialog + QAction::AboutRole @@ -460,29 +485,38 @@ &Open Database… + + Open Database + + + Ctrl+O + - - false - &Save Database + + Ctrl+S + - - false - &Close Database + + Ctrl+W + &New Database… - Create a new database + Create Database + + + Ctrl+Shift+N @@ -490,152 +524,163 @@ &Merge From Database… - Merge from another KDBX database + Merge From Database - - false - &New Entry… - Add a new entry + Create Entry + + + Ctrl+N - - false - &Edit Entry… - View or edit entry + Edit Entry + + + Ctrl+E - + false + + E&xpire Entry… + + + &Delete Entry… + + Delete Entry + + + Del + - - false - &New Group… - Add a new group + Create Group - - false - &Edit Group… + + Edit Group + - - false - &Delete Group… + + Delete Group + - - false - Download All &Favicons… + + Download All Favicons + - - false - Sort &A-Z + + Sort Groups A-Z + - - false - Sort &Z-A + + Sort Groups Z-A + - - false - Sa&ve Database As… + + Save Database As + + + Ctrl+Shift+S + - - false - Database &Security… + + Show Database Security + - - false + + true Database &Reports… - Statistics, health check, etc. + Show Database Reports + + + Ctrl+Shift+R QAction::NoRole - - false + + true &Database Settings… - Database settings + Show Database Settings + + + Ctrl+Shift+, QAction::NoRole - - false - Passkeys… - Passkeys + Show Passkeys QAction::NoRole - - false - Import Passkey @@ -647,55 +692,58 @@ - - false - &Clone Entry… + + Clone Entry + + + Ctrl+D + - - false - Move u&p - Move entry one step up + Move Entry Up + + + Alt+Up - - false - Move do&wn - Move entry one step down + Move Entry Down + + + Alt+Down - - false - Copy &Username - Copy username to clipboard + Copy Username + + + Ctrl+B - - false - Copy &Password - Copy password to clipboard + Copy Password + + + Ctrl+C @@ -705,6 +753,12 @@ &Settings + + Show Application Settings + + + Ctrl+, + QAction::PreferencesRole @@ -716,23 +770,25 @@ &Password Generator + + Show Password Generator + - - false - Perform &Auto-Type - - false - Import Passkey + + + Remove Passkey From Entry + + false @@ -744,7 +800,7 @@ {USERNAME} - {USERNAME} + Perform Auto-Type: {USERNAME} @@ -758,7 +814,7 @@ {USERNAME}{ENTER} - {USERNAME}{ENTER} + Perform Auto-Type: {USERNAME}{ENTER} @@ -772,7 +828,7 @@ {PASSWORD} - {PASSWORD} + Perform Auto-Type: {PASSWORD} @@ -786,7 +842,7 @@ {PASSWORD}{ENTER} - {PASSWORD}{ENTER} + Perform Auto-Type: {PASSWORD}{ENTER} @@ -800,93 +856,93 @@ {TOTP} - {TOTP} + Perform Auto-Type: {TOTP} Download &Favicon + + Ctrl+Shift+D + - - false - Open &URL + + Ctrl+Shift+U + - - false - &Lock Database + + Ctrl+L + - - false - Lock &All Databases + + Ctrl+Shift+L + - - false - &Title - Copy title to clipboard + Copy Title + + + Ctrl+I - - false - Copy &URL - Copy URL to clipboard + Copy URL + + + Ctrl+U - - false - &Notes - Copy notes to clipboard + Copy Notes - - false - &CSV File… + + Export to CSV + - - false - &HTML File… + + Export to HTML + KeePass 1 Database… - Import a KeePass 1 database + Import KeePass1 Database @@ -894,7 +950,7 @@ 1Password Vault… - Import a 1Password Vault + Import 1Password Vault @@ -902,51 +958,72 @@ CSV File… - Import a CSV file + Import CSV File Show TOTP + + Ctrl+Shift+T + Show QR Code + + Show TOTP QR Code + Set up TOTP… + + Set up TOTP + Copy &TOTP + + Ctrl+T + Copy Password and TOTP + + Ctrl+Y + E&mpty recycle bin - - false + + Empty Recycle Bin &Donate + + Open Donation Website + Report a &Bug + + Open Bug Report + @@ -961,7 +1038,7 @@ &Online Help - Go to online documentation + Open Online Documentation @@ -976,27 +1053,42 @@ &Keyboard Shortcuts + + Open Keyboard Shortcuts Guide + Ctrl+/ - - false - Save Database Backup… + + Save Database Backup + Add key to SSH Agent + + SSH Agent: Add Key + + + Ctrl+H + Remove key from SSH Agent + + SSH Agent: Remove Key + + + Ctrl+Shift+H + @@ -1005,6 +1097,9 @@ Compact Mode + + Toggle Compact Mode + @@ -1016,6 +1111,9 @@ Automatic + + Set Theme: Automatic + @@ -1024,6 +1122,9 @@ Light + + Set Theme: Light + @@ -1032,6 +1133,9 @@ Dark + + Set Theme: Dark + @@ -1040,6 +1144,9 @@ Classic (Platform-native) + + Set Theme: Classic + @@ -1065,6 +1172,9 @@ Show Toolbar + + Toggle Show Toolbar + @@ -1076,6 +1186,9 @@ Show Preview Panel + + Toggle Show Preview Panel + @@ -1084,6 +1197,9 @@ Always on Top + + Toggle Always on Top + Ctrl+Shift+A @@ -1095,6 +1211,9 @@ Hide Usernames + + Toggle Hide Usernames + Ctrl+Shift+B @@ -1109,6 +1228,9 @@ Hide Passwords + + Toggle Hide Passwords + Ctrl+Shift+C @@ -1121,13 +1243,13 @@ {USERNAME}{TAB}{PASSWORD}{ENTER} - {USERNAME}{TAB}{PASSWORD}{ENTER} + Perform Auto-Type: Entry Default + + + Ctrl+Shift+V - - false - Clone Group... @@ -1137,29 +1259,23 @@ Restore Entry(s) - Restore Entry(s) + Restore Entry Ctrl+R - - false - &Lock Database - - false - &XML File… - XML File… + Export to XML @@ -1169,6 +1285,9 @@ Allow Screen Capture + + Toggle Allow Screen Capture + @@ -1183,6 +1302,31 @@ Import… + + + true + + + true + + + Show Group Panel + + + Toggle Show Group Panel + + + + + Clear SSH Agent + + + Clear all identities in ssh-agent + + + QAction::TextHeuristicRole + + diff --git a/src/gui/MessageBox.cpp b/src/gui/MessageBox.cpp index a2c1498cd..87898ff5c 100644 --- a/src/gui/MessageBox.cpp +++ b/src/gui/MessageBox.cpp @@ -88,9 +88,12 @@ MessageBox::Button MessageBox::messageBox(QWidget* parent, { if (m_nextAnswer == MessageBox::NoButton) { QMessageBox msgBox(parent); + msgBox.setTextFormat(Qt::RichText); msgBox.setIcon(icon); msgBox.setWindowTitle(title); - msgBox.setText(text); + // Replace newlines with HTML line breaks + auto fixedText = text; + msgBox.setText(fixedText.replace("\n", "
    ")); if (m_overrideParent) { // Force the creation of the QWindow, without this windowHandle() will return nullptr diff --git a/src/gui/PasswordGeneratorWidget.cpp b/src/gui/PasswordGeneratorWidget.cpp index 39bdcc729..d3dd7d699 100644 --- a/src/gui/PasswordGeneratorWidget.cpp +++ b/src/gui/PasswordGeneratorWidget.cpp @@ -57,6 +57,7 @@ PasswordGeneratorWidget::PasswordGeneratorWidget(QWidget* parent) connect(m_ui->editNewPassword, SIGNAL(textChanged(QString)), SLOT(updateButtonsEnabled(QString))); connect(m_ui->editNewPassword, SIGNAL(textChanged(QString)), SLOT(updatePasswordStrength())); + connect(m_ui->editNewPassword, SIGNAL(textChanged(QString)), SLOT(updatePasswordLengthLabel(QString))); connect(m_ui->buttonAdvancedMode, SIGNAL(toggled(bool)), SLOT(setAdvancedMode(bool))); connect(m_ui->buttonAddHex, SIGNAL(clicked()), SLOT(excludeHexChars())); connect(m_ui->editAdditionalChars, SIGNAL(textChanged(QString)), SLOT(updateGenerator())); @@ -64,7 +65,7 @@ PasswordGeneratorWidget::PasswordGeneratorWidget(QWidget* parent) connect(m_ui->buttonApply, SIGNAL(clicked()), SLOT(applyPassword())); connect(m_ui->buttonCopy, SIGNAL(clicked()), SLOT(copyPassword())); connect(m_ui->buttonGenerate, SIGNAL(clicked()), SLOT(regeneratePassword())); - connect(m_ui->buttonDeleteWordList, SIGNAL(clicked()), SLOT(deleteWordList())); + connect(m_ui->buttonDeleteWordList, SIGNAL(clicked()), SLOT(removeCustomWordList())); connect(m_ui->buttonAddWordList, SIGNAL(clicked()), SLOT(addWordList())); connect(m_ui->buttonClose, SIGNAL(clicked()), SIGNAL(closed())); @@ -80,14 +81,15 @@ PasswordGeneratorWidget::PasswordGeneratorWidget(QWidget* parent) connect(m_ui->tabWidget, SIGNAL(currentChanged(int)), SLOT(updateGenerator())); connect(m_ui->wordCaseComboBox, SIGNAL(currentIndexChanged(int)), SLOT(updateGenerator())); - // set font size of password quality and entropy labels dynamically to 80% of + // set font size of password quality, characters, and entropy labels dynamically to 80% of // the default font size, but make it no smaller than 8pt QFont defaultFont; - int smallerSize = static_cast(defaultFont.pointSize() * 0.8f); + auto smallerSize = static_cast(defaultFont.pointSize() * 0.8f); if (smallerSize >= 8) { defaultFont.setPointSize(smallerSize); m_ui->entropyLabel->setFont(defaultFont); m_ui->strengthLabel->setFont(defaultFont); + m_ui->passwordLengthLabel->setFont(defaultFont); } // set default separator to Space @@ -97,6 +99,7 @@ PasswordGeneratorWidget::PasswordGeneratorWidget(QWidget* parent) m_ui->wordCaseComboBox->addItem(tr("lower case"), PassphraseGenerator::LOWERCASE); m_ui->wordCaseComboBox->addItem(tr("UPPER CASE"), PassphraseGenerator::UPPERCASE); m_ui->wordCaseComboBox->addItem(tr("Title Case"), PassphraseGenerator::TITLECASE); + m_ui->wordCaseComboBox->addItem(tr("MIXED case"), PassphraseGenerator::MIXEDCASE); // load system-wide wordlists QDir path(resources()->wordlistPath("")); @@ -112,6 +115,11 @@ PasswordGeneratorWidget::PasswordGeneratorWidget(QWidget* parent) m_ui->comboBoxWordList->addItem(fileName, path.absolutePath() + QDir::separator() + fileName); } + // Set color of wordlist warning + StateColorPalette statePalette; + auto color = statePalette.color(StateColorPalette::ColorRole::False); + m_ui->labelWordListWarning->setStyleSheet(QString("QLabel { color: %1; }").arg(color.name())); + loadSettings(); } @@ -254,9 +262,7 @@ void PasswordGeneratorWidget::regeneratePassword() m_ui->editNewPassword->setText(m_passwordGenerator->generatePassword()); } } else { - if (m_dicewareGenerator->isValid()) { - m_ui->editNewPassword->setText(m_dicewareGenerator->generatePassphrase()); - } + m_ui->editNewPassword->setText(m_dicewareGenerator->generatePassphrase()); } } @@ -274,7 +280,6 @@ void PasswordGeneratorWidget::updatePasswordStrength() PasswordHealth passwordHealth(0); if (m_ui->tabWidget->currentIndex() == Diceware) { passwordHealth.init(m_dicewareGenerator->estimateEntropy()); - m_ui->charactersInPassphraseLabel->setText(QString::number(m_ui->editNewPassword->text().length())); } else { passwordHealth = PasswordHealth(m_ui->editNewPassword->text()); } @@ -316,6 +321,11 @@ void PasswordGeneratorWidget::updatePasswordStrength() } } +void PasswordGeneratorWidget::updatePasswordLengthLabel(const QString& password) +{ + m_ui->passwordLengthLabel->setText(tr("Characters: %1").arg(QString::number(password.length()))); +} + void PasswordGeneratorWidget::applyPassword() { saveSettings(); @@ -372,33 +382,28 @@ bool PasswordGeneratorWidget::isPasswordGenerated() const return m_passwordGenerated; } -void PasswordGeneratorWidget::deleteWordList() +void PasswordGeneratorWidget::removeCustomWordList() { if (m_ui->comboBoxWordList->currentIndex() < m_firstCustomWordlistIndex) { return; } - QFile file(m_ui->comboBoxWordList->currentData().toString()); - if (!file.exists()) { - return; - } - + auto wordlist = m_ui->comboBoxWordList->currentText(); auto result = MessageBox::question(this, - tr("Confirm Delete Wordlist"), - tr("Do you really want to delete the wordlist \"%1\"?").arg(file.fileName()), - MessageBox::Delete | MessageBox::Cancel, + tr("Confirm Remove Wordlist"), + tr("Do you really want to remove the wordlist \"%1\"?").arg(wordlist), + MessageBox::Remove | MessageBox::Cancel, MessageBox::Cancel); - if (result != MessageBox::Delete) { - return; - } - if (!file.remove()) { - MessageBox::critical(this, tr("Failed to delete wordlist"), file.errorString()); - return; - } + if (result == MessageBox::Remove) { + QFile file(m_ui->comboBoxWordList->currentData().toString()); + if (file.exists() && !file.remove()) { + MessageBox::critical(this, tr("Failed to delete wordlist"), file.errorString()); + } - m_ui->comboBoxWordList->removeItem(m_ui->comboBoxWordList->currentIndex()); - updateGenerator(); + m_ui->comboBoxWordList->removeItem(m_ui->comboBoxWordList->currentIndex()); + updateGenerator(); + } } void PasswordGeneratorWidget::addWordList() @@ -582,11 +587,7 @@ void PasswordGeneratorWidget::updateGenerator() } m_passwordGenerator->setFlags(flags); - if (m_passwordGenerator->isValid()) { - m_ui->buttonGenerate->setEnabled(true); - } else { - m_ui->buttonGenerate->setEnabled(false); - } + m_ui->buttonGenerate->setEnabled(m_passwordGenerator->isValid()); } else { m_dicewareGenerator->setWordCase( static_cast(m_ui->wordCaseComboBox->currentData().toInt())); @@ -603,11 +604,8 @@ void PasswordGeneratorWidget::updateGenerator() m_dicewareGenerator->setWordSeparator(m_ui->editWordSeparator->text()); - if (m_dicewareGenerator->isValid()) { - m_ui->buttonGenerate->setEnabled(true); - } else { - m_ui->buttonGenerate->setEnabled(false); - } + m_ui->labelWordListWarning->setVisible(!m_dicewareGenerator->isWordListValid()); + m_ui->buttonGenerate->setEnabled(true); } regeneratePassword(); diff --git a/src/gui/PasswordGeneratorWidget.h b/src/gui/PasswordGeneratorWidget.h index f1b9d9eef..d7496365a 100644 --- a/src/gui/PasswordGeneratorWidget.h +++ b/src/gui/PasswordGeneratorWidget.h @@ -46,7 +46,7 @@ public: }; explicit PasswordGeneratorWidget(QWidget* parent = nullptr); - ~PasswordGeneratorWidget(); + ~PasswordGeneratorWidget() override; void loadSettings(); void saveSettings(); @@ -67,7 +67,7 @@ public slots: void applyPassword(); void copyPassword(); void setPasswordVisible(bool visible); - void deleteWordList(); + void removeCustomWordList(); void addWordList(); protected: @@ -76,6 +76,7 @@ protected: private slots: void updateButtonsEnabled(const QString& password); void updatePasswordStrength(); + void updatePasswordLengthLabel(const QString& password); void setAdvancedMode(bool advanced); void excludeHexChars(); diff --git a/src/gui/PasswordGeneratorWidget.ui b/src/gui/PasswordGeneratorWidget.ui index 250f13038..eac5421cd 100644 --- a/src/gui/PasswordGeneratorWidget.ui +++ b/src/gui/PasswordGeneratorWidget.ui @@ -7,7 +7,7 @@ 0 0 729 - 427 + 433 @@ -59,6 +59,50 @@ + + + + + 0 + 0 + + + + + 70 + 0 + + + + + 16777215 + 30 + + + + passwordLength + + + Qt::AlignRight|Qt::AlignTop|Qt::AlignTrailing + + + 3 + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + @@ -672,7 +716,10 @@ QProgressBar::chunk { - Excluded characters: "0", "1", "l", "I", "O", "|", "﹒" + Excluded characters: "0", "1", "l", "I", "O", "|", "﹒", "B", "8", "G", "6" + + + Excluded characters: "0", "1", "l", "I", "O", "|", "﹒", "B", "8", "G", "6" Exclude look-alike characters @@ -722,14 +769,7 @@ QProgressBar::chunk { - - - - Word Separator: - - - - + @@ -742,7 +782,100 @@ QProgressBar::chunk { + + + + + + + 0 + 0 + + + + + 20 + 0 + + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + Word Count: + + + spinBoxLength + + + + + + + Word Case: + + + + + + + + + 0 + 0 + + + + + + + + Qt::TabFocus + + + Delete selected wordlist + + + Delete selected wordlist + + + + + + + Qt::TabFocus + + + Add custom wordlist + + + Add custom wordlist + + + + + + QLayout::SetMinimumSize @@ -787,31 +920,7 @@ QProgressBar::chunk { - - - - Word Count: - - - spinBoxLength - - - - - - - Character Count: - - - - - - - Word Case: - - - - + @@ -831,86 +940,23 @@ QProgressBar::chunk { - - - - - - - 0 - 0 - - - - - 20 - 0 - - - - - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - + + + + Word Separator: + + - - - - - - 0 - 0 - - - - - - - - Qt::TabFocus - - - Delete selected wordlist - - - Delete selected wordlist - - - - - - - Qt::TabFocus - - - Add custom wordlist - - - Add custom wordlist - - - - - - - + + + + 75 + true + + - character + Warning: the chosen wordlist is smaller than the minimum recommended size! diff --git a/src/gui/PasswordWidget.cpp b/src/gui/PasswordWidget.cpp index 2b2d9057b..2568ff67b 100644 --- a/src/gui/PasswordWidget.cpp +++ b/src/gui/PasswordWidget.cpp @@ -38,6 +38,7 @@ PasswordWidget::PasswordWidget(QWidget* parent) { m_ui->setupUi(this); setFocusProxy(m_ui->passwordEdit); + m_ui->passwordEdit->installEventFilter(this); const QIcon errorIcon = icons()->icon("dialog-error"); m_errorAction = m_ui->passwordEdit->addAction(errorIcon, QLineEdit::TrailingPosition); @@ -223,14 +224,19 @@ void PasswordWidget::updateRepeatStatus() } } -bool PasswordWidget::event(QEvent* event) +bool PasswordWidget::eventFilter(QObject* watched, QEvent* event) { - if (isVisible() - && (event->type() == QEvent::KeyPress || event->type() == QEvent::KeyRelease - || event->type() == QEvent::FocusIn)) { - checkCapslockState(); + if (watched == m_ui->passwordEdit) { + auto type = event->type(); + if (isVisible() && (type == QEvent::KeyPress || type == QEvent::KeyRelease || type == QEvent::FocusIn)) { + checkCapslockState(); + } + if (type == QEvent::FocusIn || type == QEvent::FocusOut || type == QEvent::Hide) { + osUtils->setUserInputProtection(type == QEvent::FocusIn); + } } - return QWidget::event(event); + // Continue with normal operations + return false; } void PasswordWidget::checkCapslockState() @@ -306,4 +312,4 @@ void PasswordWidget::updatePasswordStrength(const QString& password) break; } -} \ No newline at end of file +} diff --git a/src/gui/PasswordWidget.h b/src/gui/PasswordWidget.h index 5ad1c4f5c..6049d2908 100644 --- a/src/gui/PasswordWidget.h +++ b/src/gui/PasswordWidget.h @@ -44,6 +44,8 @@ public: bool isPasswordVisible() const; QString text(); + bool eventFilter(QObject* watched, QEvent* event) override; + signals: void textChanged(QString text); @@ -57,9 +59,6 @@ public slots: void setEchoMode(QLineEdit::EchoMode mode); void setClearButtonEnabled(bool enabled); -protected: - bool event(QEvent* event) override; - private slots: void popupPasswordGenerator(); void updateRepeatStatus(); diff --git a/src/gui/PasswordWidget.ui b/src/gui/PasswordWidget.ui index 34cae29e1..97fe71e08 100644 --- a/src/gui/PasswordWidget.ui +++ b/src/gui/PasswordWidget.ui @@ -29,7 +29,7 @@ - Toggle password visibilty using Control + H. Open the password generator using Control + G. + Toggle password visibility using Control + H. Open the password generator using Control + G. diff --git a/src/gui/SearchHelpWidget.ui b/src/gui/SearchHelpWidget.ui index 907b2822d..d9778fd22 100644 --- a/src/gui/SearchHelpWidget.ui +++ b/src/gui/SearchHelpWidget.ui @@ -388,7 +388,7 @@ - + 0 diff --git a/src/gui/SearchWidget.cpp b/src/gui/SearchWidget.cpp index 8178fa200..5fce8a5aa 100644 --- a/src/gui/SearchWidget.cpp +++ b/src/gui/SearchWidget.cpp @@ -16,6 +16,7 @@ */ #include "SearchWidget.h" +#include "gui/MainWindow.h" #include "ui_SearchHelpWidget.h" #include "ui_SearchWidget.h" @@ -53,6 +54,7 @@ SearchWidget::SearchWidget(QWidget* parent) connect(m_searchTimer, SIGNAL(timeout()), SLOT(startSearch())); connect(m_clearSearchTimer, SIGNAL(timeout()), SLOT(clearSearch())); connect(this, SIGNAL(escapePressed()), SLOT(clearSearch())); + connect(m_ui->searchEdit, &QLineEdit::returnPressed, this, &SearchWidget::onReturnPressed); m_ui->searchEdit->setPlaceholderText(tr("Search (%1)…", "Search placeholder text, %1 is the keyboard shortcut") .arg(QKeySequence(QKeySequence::Find).toString(QKeySequence::NativeText))); @@ -68,6 +70,12 @@ SearchWidget::SearchWidget(QWidget* parent) m_actionLimitGroup->setCheckable(true); m_actionLimitGroup->setChecked(config()->get(Config::SearchLimitGroup).toBool()); + m_actionWaitForEnter = m_searchMenu->addAction( + tr("Press Enter to search"), this, [](bool state) { config()->set(Config::SearchWaitForEnter, state); }); + m_actionWaitForEnter->setObjectName("actionSearchWaitForEnter"); + m_actionWaitForEnter->setCheckable(true); + m_actionWaitForEnter->setChecked(config()->get(Config::SearchWaitForEnter).toBool()); + m_ui->searchIcon->setIcon(icons()->icon("system-search")); m_ui->searchEdit->addAction(m_ui->searchIcon, QLineEdit::LeadingPosition); @@ -84,22 +92,31 @@ SearchWidget::SearchWidget(QWidget* parent) } } -SearchWidget::~SearchWidget() -{ -} +SearchWidget::~SearchWidget() = default; bool SearchWidget::eventFilter(QObject* obj, QEvent* event) { if (event->type() == QEvent::KeyPress) { - QKeyEvent* keyEvent = static_cast(event); + auto keyEvent = static_cast(event); if (keyEvent->key() == Qt::Key_Escape) { emit escapePressed(); return true; } else if (keyEvent->matches(QKeySequence::Copy)) { - // If Control+C is pressed in the search edit when no text - // is selected, copy the password of the current entry. + // If the system Copy shortcut (typically Ctrl+C or Cmd+C) is pressed + // in the search edit when no text is selected, route the event to the + // main window. With the default shortcut configuration, this will copy + // the password of the current entry to the clipboard. if (!m_ui->searchEdit->hasSelectedText()) { - emit copyPressed(); + // Prevent infinite recursion, in case the main window ends up + // sending this event back to us. This hasn't actually been observed + // in practice and is just a precaution. + static bool sendingCopyShortcutEvent = false; + if (sendingCopyShortcutEvent) { + return true; + } + sendingCopyShortcutEvent = true; + QCoreApplication::sendEvent(getMainWindow(), event); + sendingCopyShortcutEvent = false; return true; } } else if (keyEvent->matches(QKeySequence::MoveToNextLine)) { @@ -137,19 +154,18 @@ void SearchWidget::connectSignals(SignalMultiplexer& mx) mx.connect(this, SIGNAL(saveSearch(QString)), SLOT(saveSearch(QString))); mx.connect(this, SIGNAL(caseSensitiveChanged(bool)), SLOT(setSearchCaseSensitive(bool))); mx.connect(this, SIGNAL(limitGroupChanged(bool)), SLOT(setSearchLimitGroup(bool))); - mx.connect(this, SIGNAL(copyPressed()), SLOT(copyPassword())); mx.connect(this, SIGNAL(downPressed()), SLOT(focusOnEntries())); mx.connect(SIGNAL(requestSearch(QString)), m_ui->searchEdit, SLOT(setText(QString))); mx.connect(SIGNAL(clearSearch()), this, SLOT(clearSearch())); mx.connect(SIGNAL(entrySelectionChanged()), this, SLOT(resetSearchClearTimer())); mx.connect(SIGNAL(currentModeChanged(DatabaseWidget::Mode)), this, SLOT(resetSearchClearTimer())); mx.connect(SIGNAL(databaseUnlocked()), this, SLOT(focusSearch())); - mx.connect(m_ui->searchEdit, SIGNAL(returnPressed()), SLOT(switchToEntryEdit())); + mx.connect(this, SIGNAL(enterPressed()), SLOT(switchToEntryEdit())); } void SearchWidget::databaseChanged(DatabaseWidget* dbWidget) { - if (dbWidget != nullptr) { + if (dbWidget) { // Set current search text from this database m_ui->searchEdit->setText(dbWidget->getCurrentSearch()); // Enforce search policy @@ -162,18 +178,15 @@ void SearchWidget::databaseChanged(DatabaseWidget* dbWidget) void SearchWidget::startSearchTimer() { - if (!m_searchTimer->isActive()) { + if (m_actionWaitForEnter->isChecked()) { m_searchTimer->stop(); + } else { + m_searchTimer->start(500); } - m_searchTimer->start(100); } void SearchWidget::startSearch() { - if (!m_searchTimer->isActive()) { - m_searchTimer->stop(); - } - m_ui->saveIcon->setVisible(true); search(m_ui->searchEdit->text()); } @@ -191,18 +204,18 @@ void SearchWidget::updateCaseSensitive() emit caseSensitiveChanged(m_actionCaseSensitive->isChecked()); } -void SearchWidget::setCaseSensitive(bool state) -{ - m_actionCaseSensitive->setChecked(state); - updateCaseSensitive(); -} - void SearchWidget::updateLimitGroup() { config()->set(Config::SearchLimitGroup, m_actionLimitGroup->isChecked()); emit limitGroupChanged(m_actionLimitGroup->isChecked()); } +void SearchWidget::setCaseSensitive(bool state) +{ + m_actionCaseSensitive->setChecked(state); + updateCaseSensitive(); +} + void SearchWidget::setLimitGroup(bool state) { m_actionLimitGroup->setChecked(state); @@ -235,3 +248,12 @@ void SearchWidget::showSearchMenu() { m_searchMenu->exec(m_ui->searchEdit->mapToGlobal(m_ui->searchEdit->rect().bottomLeft())); } + +void SearchWidget::onReturnPressed() +{ + if (m_actionWaitForEnter->isChecked()) { + emit search(m_ui->searchEdit->text()); + } else { + emit enterPressed(); + } +} diff --git a/src/gui/SearchWidget.h b/src/gui/SearchWidget.h index 55edad583..1d048d12b 100644 --- a/src/gui/SearchWidget.h +++ b/src/gui/SearchWidget.h @@ -57,7 +57,6 @@ signals: void caseSensitiveChanged(bool state); void limitGroupChanged(bool state); void escapePressed(); - void copyPressed(); void downPressed(); void enterPressed(); void lostFocus(); @@ -69,6 +68,7 @@ public slots: void clearSearch(); private slots: + void onReturnPressed(); void startSearchTimer(); void startSearch(); void updateCaseSensitive(); @@ -84,6 +84,7 @@ private: QTimer* m_clearSearchTimer; QAction* m_actionCaseSensitive; QAction* m_actionLimitGroup; + QAction* m_actionWaitForEnter; QMenu* m_searchMenu; }; diff --git a/src/gui/settings/SettingsWidget.cpp b/src/gui/SettingsWidget.cpp similarity index 89% rename from src/gui/settings/SettingsWidget.cpp rename to src/gui/SettingsWidget.cpp index 28f104273..fac3362c6 100644 --- a/src/gui/settings/SettingsWidget.cpp +++ b/src/gui/SettingsWidget.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2018 KeePassXC Team + * Copyright (C) 2023 KeePassXC Team * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -22,10 +22,6 @@ SettingsWidget::SettingsWidget(QWidget* parent) { } -SettingsWidget::~SettingsWidget() -{ -} - void SettingsWidget::discard() { } diff --git a/src/gui/settings/SettingsWidget.h b/src/gui/SettingsWidget.h similarity index 91% rename from src/gui/settings/SettingsWidget.h rename to src/gui/SettingsWidget.h index 90d8161df..cdbcf9cbc 100644 --- a/src/gui/settings/SettingsWidget.h +++ b/src/gui/SettingsWidget.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2018 KeePassXC Team + * Copyright (C) 2023 KeePassXC Team * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -31,8 +31,7 @@ class SettingsWidget : public QWidget public: explicit SettingsWidget(QWidget* parent = nullptr); - Q_DISABLE_COPY(SettingsWidget); - ~SettingsWidget() override; + ~SettingsWidget() override = default; public slots: /** @@ -50,7 +49,7 @@ public slots: * * @return true on success, false on failure */ - virtual bool save() = 0; + virtual bool saveSettings() = 0; /** * Discard settings. @@ -62,6 +61,8 @@ signals: private: bool m_advancedMode = false; + + Q_DISABLE_COPY(SettingsWidget); }; #endif // KEEPASSXC_SETTINGSWIDGET_H diff --git a/src/gui/ShortcutSettingsPage.cpp b/src/gui/ShortcutSettingsPage.cpp new file mode 100644 index 000000000..ffc6d32e8 --- /dev/null +++ b/src/gui/ShortcutSettingsPage.cpp @@ -0,0 +1,280 @@ +/* + * Copyright (C) 2024 KeePassXC Team + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "ShortcutSettingsPage.h" + +#include "core/Config.h" +#include "gui/ActionCollection.h" +#include "gui/Icons.h" +#include "gui/MessageBox.h" +#include "gui/widgets/ShortcutWidget.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +class KeySequenceDialog final : public QDialog +{ +public: + explicit KeySequenceDialog(QWidget* parent = nullptr) + : QDialog(parent) + , m_keySeqEdit(new ShortcutWidget(this)) + , m_btnBox(new QDialogButtonBox(QDialogButtonBox::Save | QDialogButtonBox::Cancel + | QDialogButtonBox::RestoreDefaults, + this)) + { + auto* l = new QVBoxLayout(this); + connect(m_btnBox, &QDialogButtonBox::accepted, this, &QDialog::accept); + connect(m_btnBox, &QDialogButtonBox::rejected, this, &QDialog::reject); + connect(m_btnBox, &QDialogButtonBox::clicked, this, &KeySequenceDialog::restoreDefault); + + auto hLayout = new QHBoxLayout(); + l->addLayout(hLayout); + hLayout->addWidget(new QLabel(QObject::tr("Enter Shortcut"))); + hLayout->addWidget(m_keySeqEdit); + + l->addStretch(); + l->addWidget(m_btnBox); + + setFocusProxy(m_keySeqEdit); + } + + QKeySequence keySequence() const + { + return m_keySeqEdit->sequence(); + } + + bool shouldRestoreDefault() const + { + return m_restoreDefault; + } + +private: + void restoreDefault(QAbstractButton* btn) + { + if (m_btnBox->standardButton(btn) == QDialogButtonBox::RestoreDefaults) { + m_restoreDefault = true; + reject(); + } + } + + bool m_restoreDefault = false; + ShortcutWidget* const m_keySeqEdit; + QDialogButtonBox* const m_btnBox; +}; + +class ShortcutSettingsWidget final : public QWidget +{ +public: + explicit ShortcutSettingsWidget(QWidget* parent = nullptr) + : QWidget(parent) + , m_tableView(new QTableView(this)) + , m_filterLineEdit(new QLineEdit(this)) + , m_resetShortcutsButton(new QPushButton(QObject::tr("Reset Shortcuts"), this)) + { + auto h = new QHBoxLayout(); + h->addWidget(m_filterLineEdit); + h->addWidget(m_resetShortcutsButton); + h->setStretch(0, 1); + + auto l = new QVBoxLayout(this); + l->addWidget(new QLabel(QObject::tr("Double click an action to change its shortcut"))); + l->addLayout(h); + l->addWidget(m_tableView); + + m_model.setColumnCount(2); + m_model.setHorizontalHeaderLabels({QObject::tr("Action"), QObject::tr("Shortcuts")}); + + m_proxy.setFilterKeyColumn(-1); + m_proxy.setFilterCaseSensitivity(Qt::CaseInsensitive); + m_proxy.setSourceModel(&m_model); + + m_filterLineEdit->setPlaceholderText(QObject::tr("Filter...")); + connect(m_filterLineEdit, &QLineEdit::textChanged, &m_proxy, &QSortFilterProxyModel::setFilterFixedString); + + connect(m_resetShortcutsButton, &QPushButton::clicked, this, [this]() { + auto ac = ActionCollection::instance(); + for (auto action : ac->actions()) { + action->setShortcut(ac->defaultShortcut(action)); + } + loadSettings(); + }); + + m_tableView->setModel(&m_proxy); + m_tableView->setSortingEnabled(true); + m_tableView->sortByColumn(0, Qt::AscendingOrder); + m_tableView->horizontalHeader()->setSectionResizeMode(0, QHeaderView::ResizeToContents); + m_tableView->horizontalHeader()->setSectionResizeMode(1, QHeaderView::Stretch); + m_tableView->verticalHeader()->hide(); + m_tableView->setEditTriggers(QAbstractItemView::NoEditTriggers); + m_tableView->setSelectionMode(QAbstractItemView::SingleSelection); + m_tableView->setSelectionBehavior(QAbstractItemView::SelectRows); + + connect(m_tableView, &QTableView::doubleClicked, this, &ShortcutSettingsWidget::onDoubleClicked); + } + + void loadSettings() + { + m_changedActions.clear(); + m_filterLineEdit->clear(); + m_model.setRowCount(0); + const auto& actions = ActionCollection::instance()->actions(); + for (auto a : actions) { + auto name = a->toolTip().isEmpty() ? acceleratorsStrippedText(a->text()) : a->toolTip(); + auto col1 = new QStandardItem(name); + col1->setData(QVariant::fromValue(a), Qt::UserRole); + auto col2 = new QStandardItem(a->shortcut().toString()); + m_model.appendRow({col1, col2}); + } + } + + void saveSettings() + { + if (m_changedActions.count()) { + for (const auto& action : m_changedActions.keys()) { + action->setShortcut(m_changedActions.value(action)); + } + ActionCollection::instance()->saveShortcuts(); + } + m_changedActions.clear(); + m_filterLineEdit->clear(); + } + +private: + static QString acceleratorsStrippedText(QString text) + { + for (int i = 0; i < text.size(); ++i) { + if (text.at(i) == QLatin1Char('&') && i + 1 < text.size() && text.at(i + 1) != QLatin1Char('&')) { + text.remove(i, 1); + } + } + return text; + } + + void onDoubleClicked(QModelIndex index) + { + if (index.column() != 0) { + index = index.sibling(index.row(), 0); + } + index = m_proxy.mapToSource(index); + auto action = index.data(Qt::UserRole).value(); + + KeySequenceDialog dialog(this); + int ret = dialog.exec(); + + QKeySequence change; + if (ret == QDialog::Accepted) { + change = dialog.keySequence(); + } else if (dialog.shouldRestoreDefault()) { + change = ActionCollection::instance()->defaultShortcut(action); + } else { + // Rejected + return; + } + + auto conflict = ActionCollection::instance()->isConflictingShortcut(action, change); + bool hasConflict = false; + if (conflict) { + // we conflicted with an action inside action collection + // check if the conflicted action is updated here + if (!m_changedActions.contains(conflict)) { + hasConflict = true; + } else { + if (m_changedActions.value(conflict) == change) { + hasConflict = true; + } + } + } else if (!change.isEmpty()) { + // we did not conflict with any shortcut inside action collection + // check if we conflict with any locally modified action + for (auto chAction : m_changedActions.keys()) { + if (m_changedActions.value(chAction) == change) { + hasConflict = true; + conflict = chAction; + break; + } + } + } + + if (hasConflict) { + auto conflictName = + conflict->toolTip().isEmpty() ? acceleratorsStrippedText(conflict->text()) : conflict->toolTip(); + auto conflictSeq = change.toString(); + + auto ans = MessageBox::question( + this, + QObject::tr("Shortcut Conflict"), + QObject::tr("Shortcut %1 conflicts with '%2'. Overwrite shortcut?").arg(conflictSeq, conflictName), + MessageBox::Overwrite | MessageBox::Discard, + MessageBox::Discard); + if (ans == MessageBox::Discard) { + // Bail out before making any changes + return; + } + + // Reset the conflict shortcut + m_changedActions[conflict] = {}; + for (auto item : m_model.findItems(conflictSeq, Qt::MatchExactly, 1)) { + item->setText(""); + } + } + + m_changedActions[action] = change; + auto item = m_model.itemFromIndex(index.sibling(index.row(), 1)); + item->setText(change.toString()); + } + + QTableView* m_tableView; + QLineEdit* m_filterLineEdit; + QPushButton* m_resetShortcutsButton; + QStandardItemModel m_model; + QSortFilterProxyModel m_proxy; + QHash m_changedActions; +}; + +QString ShortcutSettingsPage::name() +{ + return QObject::tr("Shortcuts"); +} + +QIcon ShortcutSettingsPage::icon() +{ + return icons()->icon("auto-type"); +} + +QWidget* ShortcutSettingsPage::createWidget() +{ + return new ShortcutSettingsWidget(); +} + +void ShortcutSettingsPage::loadSettings(QWidget* widget) +{ + static_cast(widget)->loadSettings(); +} + +void ShortcutSettingsPage::saveSettings(QWidget* widget) +{ + static_cast(widget)->saveSettings(); +} diff --git a/src/keeshare/DatabaseSettingsPageKeeShare.h b/src/gui/ShortcutSettingsPage.h similarity index 57% rename from src/keeshare/DatabaseSettingsPageKeeShare.h rename to src/gui/ShortcutSettingsPage.h index 1de48eae8..c5ce5fa38 100644 --- a/src/keeshare/DatabaseSettingsPageKeeShare.h +++ b/src/gui/ShortcutSettingsPage.h @@ -1,10 +1,10 @@ /* - * Copyright (C) 2018 KeePassXC Team + * Copyright (C) 2024 KeePassXC Team * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 2 or (at your option) - * version 3 of the License. + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -15,19 +15,22 @@ * along with this program. If not, see . */ -#ifndef KEEPASSXC_DATABASESETTINGSPAGEKEESHARE_H -#define KEEPASSXC_DATABASESETTINGSPAGEKEESHARE_H +#ifndef KEEPASSXC_SHORTCUT_SETTINGSPAGE_H +#define KEEPASSXC_SHORTCUT_SETTINGSPAGE_H -#include "gui/dbsettings/DatabaseSettingsDialog.h" +#include "gui/ApplicationSettingsWidget.h" -class DatabaseSettingsPageKeeShare : public IDatabaseSettingsPage +class ShortcutSettingsPage : public ISettingsPage { public: + explicit ShortcutSettingsPage() = default; + ~ShortcutSettingsPage() override = default; + QString name() override; QIcon icon() override; QWidget* createWidget() override; - void loadSettings(QWidget* widget, QSharedPointer db) override; + void loadSettings(QWidget* widget) override; void saveSettings(QWidget* widget) override; }; -#endif // KEEPASSXC_DATABASESETTINGSPAGEKEESHARE_H +#endif // KEEPASSXC_BROWSERSETTINGSPAGE_H diff --git a/src/gui/TotpDialog.cpp b/src/gui/TotpDialog.cpp index 577fa1056..7b794c08d 100644 --- a/src/gui/TotpDialog.cpp +++ b/src/gui/TotpDialog.cpp @@ -39,6 +39,7 @@ TotpDialog::TotpDialog(QWidget* parent, Entry* entry) m_step = m_entry->totpSettings()->step; resetCounter(); updateProgressBar(); + updateSeconds(); connect(&m_totpUpdateTimer, SIGNAL(timeout()), this, SLOT(updateProgressBar())); connect(&m_totpUpdateTimer, SIGNAL(timeout()), this, SLOT(updateSeconds())); @@ -53,9 +54,7 @@ TotpDialog::TotpDialog(QWidget* parent, Entry* entry) connect(m_ui->buttonBox, SIGNAL(accepted()), SLOT(copyToClipboard())); } -TotpDialog::~TotpDialog() -{ -} +TotpDialog::~TotpDialog() = default; void TotpDialog::copyToClipboard() { @@ -90,10 +89,15 @@ void TotpDialog::updateSeconds() void TotpDialog::updateTotp() { - QString totpCode = m_entry->totp(); - QString firstHalf = totpCode.left(totpCode.size() / 2); - QString secondHalf = totpCode.mid(totpCode.size() / 2); - m_ui->totpLabel->setText(firstHalf + " " + secondHalf); + bool isValid = false; + QString totpCode = m_entry->totp(&isValid); + if (isValid) { + totpCode.insert(totpCode.size() / 2, " "); + } + m_ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(isValid); + m_ui->progressBar->setVisible(isValid); + m_ui->timerLabel->setVisible(isValid); + m_ui->totpLabel->setText(totpCode); } void TotpDialog::resetCounter() diff --git a/src/gui/TotpDialog.h b/src/gui/TotpDialog.h index d64549759..cc30a081e 100644 --- a/src/gui/TotpDialog.h +++ b/src/gui/TotpDialog.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2017 Weslly Honorato <weslly@protonmail.com> + * Copyright (C) 2017 Weslly Honorato * Copyright (C) 2017 KeePassXC Team * * This program is free software: you can redistribute it and/or modify diff --git a/src/gui/TotpExportSettingsDialog.cpp b/src/gui/TotpExportSettingsDialog.cpp index 0568996b1..66d6fb1d2 100644 --- a/src/gui/TotpExportSettingsDialog.cpp +++ b/src/gui/TotpExportSettingsDialog.cpp @@ -71,7 +71,7 @@ TotpExportSettingsDialog::TotpExportSettingsDialog(DatabaseWidget* parent, Entry m_timer->start(1000); const auto totpSettings = entry->totpSettings(); - if (totpSettings->custom || !totpSettings->encoder.shortName.isEmpty()) { + if (Totp::hasCustomSettings(totpSettings) || !totpSettings->encoder.shortName.isEmpty()) { m_warningLabel->setWordWrap(true); m_warningLabel->setMargin(5); m_warningLabel->setText(tr("NOTE: These TOTP settings are custom and may not work with other authenticators.", @@ -87,7 +87,7 @@ TotpExportSettingsDialog::TotpExportSettingsDialog(DatabaseWidget* parent, Entry QBuffer buffer; qrc.writeSvg(&buffer, logicalDpiX()); m_totpSvgWidget->load(buffer.data()); - const int minsize = static_cast(logicalDpiX() * 2.5); + const auto minsize = static_cast(logicalDpiX() * 2.5); m_totpSvgWidget->setMinimumSize(minsize, minsize); } else { auto errorBox = new QMessageBox(parent); diff --git a/src/gui/TotpExportSettingsDialog.h b/src/gui/TotpExportSettingsDialog.h index ff8308d82..c36836f1a 100644 --- a/src/gui/TotpExportSettingsDialog.h +++ b/src/gui/TotpExportSettingsDialog.h @@ -34,7 +34,7 @@ class TotpExportSettingsDialog : public QDialog public: explicit TotpExportSettingsDialog(DatabaseWidget* parent = nullptr, Entry* entry = nullptr); - ~TotpExportSettingsDialog(); + ~TotpExportSettingsDialog() override; private slots: void copyToClipboard(); diff --git a/src/gui/TotpSetupDialog.cpp b/src/gui/TotpSetupDialog.cpp index e796e1d5e..e7e0bd749 100644 --- a/src/gui/TotpSetupDialog.cpp +++ b/src/gui/TotpSetupDialog.cpp @@ -29,11 +29,7 @@ TotpSetupDialog::TotpSetupDialog(QWidget* parent, Entry* entry) { m_ui->setupUi(this); setAttribute(Qt::WA_DeleteOnClose); -#if QT_VERSION >= QT_VERSION_CHECK(5, 9, 0) setWindowFlag(Qt::WindowContextHelpButtonHint, false); -#else - setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint); -#endif setFixedSize(sizeHint()); connect(m_ui->buttonBox, SIGNAL(rejected()), SLOT(close())); @@ -43,9 +39,7 @@ TotpSetupDialog::TotpSetupDialog(QWidget* parent, Entry* entry) init(); } -TotpSetupDialog::~TotpSetupDialog() -{ -} +TotpSetupDialog::~TotpSetupDialog() = default; void TotpSetupDialog::saveSettings() { @@ -114,6 +108,7 @@ void TotpSetupDialog::init() m_ui->algorithmComboBox->addItem(item.first, item.second); } m_ui->algorithmComboBox->setCurrentIndex(0); + m_ui->invalidKeyLabel->setVisible(false); // Read entry totp settings auto settings = m_entry->totpSettings(); @@ -125,7 +120,7 @@ void TotpSetupDialog::init() if (settings->encoder.shortName == Totp::STEAM_SHORTNAME) { m_ui->radioSteam->setChecked(true); - } else if (settings->custom) { + } else if (Totp::hasCustomSettings(settings)) { m_ui->radioCustom->setChecked(true); m_ui->digitsSpinBox->setValue(settings->digits); int index = m_ui->algorithmComboBox->findData(settings->algorithm); @@ -133,5 +128,8 @@ void TotpSetupDialog::init() m_ui->algorithmComboBox->setCurrentIndex(index); } } + + auto error = Totp::checkValidSettings(settings); + m_ui->invalidKeyLabel->setVisible(!error.isEmpty()); } } diff --git a/src/gui/TotpSetupDialog.h b/src/gui/TotpSetupDialog.h index 3822f119f..8b88cb8e0 100644 --- a/src/gui/TotpSetupDialog.h +++ b/src/gui/TotpSetupDialog.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2017 Weslly Honorato <weslly@protonmail.com> + * Copyright (C) 2017 Weslly Honorato * Copyright (C) 2017 KeePassXC Team * * This program is free software: you can redistribute it and/or modify diff --git a/src/gui/TotpSetupDialog.ui b/src/gui/TotpSetupDialog.ui index ab15b8ea8..f8c95f4c4 100644 --- a/src/gui/TotpSetupDialog.ui +++ b/src/gui/TotpSetupDialog.ui @@ -14,6 +14,22 @@ Setup TOTP + + + + + 75 + true + + + + Error: secret key is invalid + + + Qt::AlignCenter + + + @@ -210,6 +226,7 @@ customSettingsGroup buttonBox groupBox + invalidKeyLabel seedEdit diff --git a/src/gui/URLEdit.cpp b/src/gui/URLEdit.cpp index f5fbbb24b..fed277f00 100644 --- a/src/gui/URLEdit.cpp +++ b/src/gui/URLEdit.cpp @@ -18,9 +18,8 @@ #include "URLEdit.h" -#include "core/Tools.h" -#include "core/UrlTools.h" #include "gui/Icons.h" +#include "gui/UrlTools.h" #include "gui/styles/StateColorPalette.h" URLEdit::URLEdit(QWidget* parent) diff --git a/src/gui/UpdateCheckDialog.cpp b/src/gui/UpdateCheckDialog.cpp index da3169901..6d7015f73 100644 --- a/src/gui/UpdateCheckDialog.cpp +++ b/src/gui/UpdateCheckDialog.cpp @@ -22,7 +22,7 @@ #include "config-keepassx.h" #include "gui/Icons.h" -#include "updatecheck/UpdateChecker.h" +#include "networking/UpdateChecker.h" UpdateCheckDialog::UpdateCheckDialog(QWidget* parent) : QDialog(parent) diff --git a/src/core/UrlTools.cpp b/src/gui/UrlTools.cpp similarity index 74% rename from src/core/UrlTools.cpp rename to src/gui/UrlTools.cpp index 508bbefda..917f2048c 100644 --- a/src/core/UrlTools.cpp +++ b/src/gui/UrlTools.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2023 KeePassXC Team + * Copyright (C) 2025 KeePassXC Team * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -24,6 +24,8 @@ #include #include +const QString UrlTools::URL_WILDCARD = "1kpxcwc1"; + Q_GLOBAL_STATIC(UrlTools, s_urlTools) UrlTools* UrlTools::instance() @@ -137,8 +139,9 @@ bool UrlTools::isUrlIdentical(const QString& first, const QString& second) const return false; } - const auto firstUrl = trimUrl(first); - const auto secondUrl = trimUrl(second); + // Replace URL wildcards for comparison if found + const auto firstUrl = trimUrl(QString(first).replace("*", UrlTools::URL_WILDCARD)); + const auto secondUrl = trimUrl(QString(second).replace("*", UrlTools::URL_WILDCARD)); if (firstUrl == secondUrl) { return true; } @@ -146,27 +149,61 @@ bool UrlTools::isUrlIdentical(const QString& first, const QString& second) const return QUrl(firstUrl).matches(QUrl(secondUrl), QUrl::StripTrailingSlash); } -bool UrlTools::isUrlValid(const QString& urlField) const +bool UrlTools::isUrlValid(const QString& urlField, bool looseComparison) const { if (urlField.isEmpty() || urlField.startsWith("cmd://", Qt::CaseInsensitive) || urlField.startsWith("kdbx://", Qt::CaseInsensitive) || urlField.startsWith("{REF:A", Qt::CaseInsensitive)) { return true; } - QUrl url; - if (urlField.contains("://")) { - url = urlField; - } else { - url = QUrl::fromUserInput(urlField); + auto url = urlField; + + // Loose comparison that allows wildcards and exact URL inside " characters + if (looseComparison) { + // Exact URL + if (url.startsWith("\"") && url.endsWith("\"")) { + // Do not allow exact URL with wildcards, or empty exact URL + if (url.contains("*") || url.length() == 2) { + return false; + } + + // Get the URL inside "" + url.remove(0, 1); + url.remove(url.length() - 1, 1); + } else { + // Do not allow URL with just wildcards, or double wildcards + if (url.length() == url.count("*") || url.contains("**") || url.contains("*.*")) { + return false; + } + + url.replace("*", UrlTools::URL_WILDCARD); + } } - if (url.scheme() != "file" && url.host().isEmpty()) { + QUrl qUrl; + if (urlField.contains("://")) { + qUrl = url; + } else { + qUrl = QUrl::fromUserInput(url); + } + + if (qUrl.scheme() != "file" && qUrl.host().isEmpty()) { return false; } +#if defined(WITH_XC_NETWORKING) || defined(WITH_XC_BROWSER) + // Prevent TLD wildcards + if (looseComparison && url.contains(UrlTools::URL_WILDCARD)) { + const auto tld = getTopLevelDomainFromUrl(url); + if (tld.contains(UrlTools::URL_WILDCARD) || qUrl.host() == QString("%1.%2").arg(UrlTools::URL_WILDCARD, tld)) { + return false; + } + } +#endif + // Check for illegal characters. Adds also the wildcard * to the list QRegularExpression re("[<>\\^`{|}\\*]"); - auto match = re.match(urlField); + auto match = re.match(url); if (match.hasMatch()) { return false; } diff --git a/src/core/UrlTools.h b/src/gui/UrlTools.h similarity index 86% rename from src/core/UrlTools.h rename to src/gui/UrlTools.h index 9a229e39f..5cadb45d8 100644 --- a/src/core/UrlTools.h +++ b/src/gui/UrlTools.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2024 KeePassXC Team + * Copyright (C) 2025 KeePassXC Team * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -19,10 +19,12 @@ #define KEEPASSXC_URLTOOLS_H #include "config-keepassx.h" -#include #include #include #include +#if defined(WITH_XC_NETWORKING) || defined(WITH_XC_BROWSER) +#include +#endif class UrlTools : public QObject { @@ -39,9 +41,11 @@ public: bool isIpAddress(const QString& host) const; #endif bool isUrlIdentical(const QString& first, const QString& second) const; - bool isUrlValid(const QString& urlField) const; + bool isUrlValid(const QString& urlField, bool looseComparison = false) const; bool domainHasIllegalCharacters(const QString& domain) const; + static const QString URL_WILDCARD; + private: QUrl convertVariantToUrl(const QVariant& var) const; diff --git a/src/gui/WelcomeWidget.cpp b/src/gui/WelcomeWidget.cpp index 03f3925a6..98b0e360e 100644 --- a/src/gui/WelcomeWidget.cpp +++ b/src/gui/WelcomeWidget.cpp @@ -38,8 +38,11 @@ WelcomeWidget::WelcomeWidget(QWidget* parent) m_ui->iconLabel->setPixmap(icons()->applicationIcon().pixmap(64)); m_ui->buttonNewDatabase->setIcon(icons()->icon("document-new")); + m_ui->buttonNewDatabase->setStyleSheet("text-align:center;"); m_ui->buttonOpenDatabase->setIcon(icons()->icon("document-open")); + m_ui->buttonOpenDatabase->setStyleSheet("text-align:center;"); m_ui->buttonImport->setIcon(icons()->icon("document-import")); + m_ui->buttonImport->setStyleSheet("text-align:center;"); refreshLastDatabases(); @@ -52,9 +55,7 @@ WelcomeWidget::WelcomeWidget(QWidget* parent) SLOT(openDatabaseFromFile(QListWidgetItem*))); } -WelcomeWidget::~WelcomeWidget() -{ -} +WelcomeWidget::~WelcomeWidget() = default; void WelcomeWidget::openDatabaseFromFile(QListWidgetItem* item) { @@ -83,7 +84,7 @@ void WelcomeWidget::refreshLastDatabases() m_ui->recentListWidget->clear(); const QStringList lastDatabases = config()->get(Config::LastDatabases).toStringList(); for (const QString& database : lastDatabases) { - QListWidgetItem* itm = new QListWidgetItem; + auto itm = new QListWidgetItem; itm->setText(database); m_ui->recentListWidget->addItem(itm); } diff --git a/src/gui/WelcomeWidget.h b/src/gui/WelcomeWidget.h index 15c3da7ff..ed92c7b4b 100644 --- a/src/gui/WelcomeWidget.h +++ b/src/gui/WelcomeWidget.h @@ -32,7 +32,7 @@ class WelcomeWidget : public QWidget public: explicit WelcomeWidget(QWidget* parent = nullptr); - ~WelcomeWidget(); + ~WelcomeWidget() override; void refreshLastDatabases(); signals: diff --git a/src/gui/csvImport/CsvImportWidget.cpp b/src/gui/csvImport/CsvImportWidget.cpp index a5c8e6d39..cbabd3138 100644 --- a/src/gui/csvImport/CsvImportWidget.cpp +++ b/src/gui/csvImport/CsvImportWidget.cpp @@ -17,6 +17,7 @@ */ #include "CsvImportWidget.h" + #include "ui_CsvImportWidget.h" #include "core/Clock.h" @@ -25,6 +26,7 @@ #include "core/Totp.h" #include "format/CsvParser.h" #include "format/KeePass2Writer.h" +#include "gui/MessageBox.h" #include "gui/csvImport/CsvParserModel.h" #include @@ -39,7 +41,7 @@ namespace return group; } - auto nameList = groupPath.split("/", QString::SkipEmptyParts); + auto nameList = groupPath.split("/", Qt::SkipEmptyParts); // Skip over first group name if root if (nameList.first().compare("root", Qt::CaseInsensitive) == 0) { nameList.removeFirst(); @@ -73,18 +75,14 @@ CsvImportWidget::CsvImportWidget(QWidget* parent) m_ui->tableViewFields->setFocusPolicy(Qt::NoFocus); m_columnHeader << QObject::tr("Group") << QObject::tr("Title") << QObject::tr("Username") << QObject::tr("Password") - << QObject::tr("URL") << QObject::tr("Notes") << QObject::tr("TOTP") << QObject::tr("Icon") - << QObject::tr("Last Modified") << QObject::tr("Created"); + << QObject::tr("URL") << QObject::tr("Tags") << QObject::tr("Notes") << QObject::tr("TOTP") + << QObject::tr("Icon") << QObject::tr("Last Modified") << QObject::tr("Created"); - m_fieldSeparatorList << "," - << ";" - << "-" - << ":" - << "." - << "\t"; + m_fieldSeparatorList << "," << ";" << "-" << ":" << "." << "\t"; m_combos << m_ui->groupCombo << m_ui->titleCombo << m_ui->usernameCombo << m_ui->passwordCombo << m_ui->urlCombo - << m_ui->notesCombo << m_ui->totpCombo << m_ui->iconCombo << m_ui->lastModifiedCombo << m_ui->createdCombo; + << m_ui->tagsCombo << m_ui->notesCombo << m_ui->totpCombo << m_ui->iconCombo << m_ui->lastModifiedCombo + << m_ui->createdCombo; for (auto combo : m_combos) { combo->setModel(m_comboModel); @@ -116,9 +114,7 @@ void CsvImportWidget::skippedChanged(int rows) updateTableview(); } -CsvImportWidget::~CsvImportWidget() -{ -} +CsvImportWidget::~CsvImportWidget() = default; void CsvImportWidget::configParser() { @@ -151,6 +147,13 @@ void CsvImportWidget::updatePreview() m_ui->spinBoxSkip->setRange(minSkip, qMax(minSkip, m_parserModel->rowCount() - 1)); m_ui->spinBoxSkip->setValue(minSkip); + // Store the previous column information for comparison later + auto prevColumns = m_comboModel->stringList(); + QList prevComboIndexes; + for (auto combo : m_combos) { + prevComboIndexes << combo->currentIndex(); + } + QStringList csvColumns(tr("Not Present")); auto parser = m_parserModel->parser(); for (int i = 0; i < parser->getCsvCols(); ++i) { @@ -165,6 +168,8 @@ void CsvImportWidget::updatePreview() csvColumns << QString(tr("Column %1").arg(i)); } } + // Before setting new columns, see if they changed + bool newColumns = prevColumns != csvColumns; m_comboModel->setStringList(csvColumns); // Try to match named columns to the combo boxes @@ -183,9 +188,10 @@ void CsvImportWidget::updatePreview() break; } } - // Named column not found, default to "Not Present" + // Named column not found, default to "Not Present" or previous index if (!found) { - m_combos.at(i)->setCurrentIndex(0); + auto idx = newColumns ? 0 : prevComboIndexes.at(i); + m_combos.at(i)->setCurrentIndex(idx); } } @@ -202,32 +208,46 @@ void CsvImportWidget::load(const QString& filename) void CsvImportWidget::parse() { - configParser(); + // Hide any previous messages + emit message(""); + QApplication::setOverrideCursor(Qt::WaitCursor); QApplication::processEvents(); - bool good = m_parserModel->parse(); - updatePreview(); - QApplication::restoreOverrideCursor(); - if (!good) { + + configParser(); + if (!m_parserModel->parse()) { emit message(tr("Failed to parse CSV file: %1").arg(formatStatusText())); } + updatePreview(); + + QApplication::restoreOverrideCursor(); } QSharedPointer CsvImportWidget::buildDatabase() { + // Warn if the title column wasn't specified + if (m_combos[1]->currentIndex() == 0) { + auto ans = MessageBox::question( + this, + tr("No Title Selected"), + tr("No title column was selected, entries will be hard to tell apart.\nAre you sure you want to import?"), + MessageBox::Continue | MessageBox::Cancel); + if (ans == MessageBox::Cancel) { + return {}; + } + } + auto db = QSharedPointer::create(); db->rootGroup()->setNotes(tr("Imported from CSV file: %1").arg(m_filename)); - for (int r = 0; r < m_parserModel->rowCount(); ++r) { - // use validity of second column as a GO/NOGO for all others fields - if (!m_parserModel->data(m_parserModel->index(r, 1)).isValid()) { - continue; - } + auto rows = m_parserModel->rowCount() - m_parserModel->skippedRows(); + for (int r = 0; r < rows; ++r) { auto group = createGroupStructure(db.data(), m_parserModel->data(m_parserModel->index(r, 0)).toString()); if (!group) { continue; } + // Standard entry fields auto entry = new Entry(); entry->setUuid(QUuid::createUuid()); entry->setGroup(group); @@ -235,9 +255,11 @@ QSharedPointer CsvImportWidget::buildDatabase() entry->setUsername(m_parserModel->data(m_parserModel->index(r, 2)).toString()); entry->setPassword(m_parserModel->data(m_parserModel->index(r, 3)).toString()); entry->setUrl(m_parserModel->data(m_parserModel->index(r, 4)).toString()); - entry->setNotes(m_parserModel->data(m_parserModel->index(r, 5)).toString()); + entry->setTags(m_parserModel->data(m_parserModel->index(r, 5)).toString()); + entry->setNotes(m_parserModel->data(m_parserModel->index(r, 6)).toString()); - auto otpString = m_parserModel->data(m_parserModel->index(r, 6)); + // TOTP + auto otpString = m_parserModel->data(m_parserModel->index(r, 7)); if (otpString.isValid() && !otpString.toString().isEmpty()) { auto totp = Totp::parseSettings(otpString.toString()); if (!totp || totp->key.isEmpty()) { @@ -247,14 +269,16 @@ QSharedPointer CsvImportWidget::buildDatabase() entry->setTotp(totp); } + // Icon bool ok; - int icon = m_parserModel->data(m_parserModel->index(r, 7)).toInt(&ok); + int icon = m_parserModel->data(m_parserModel->index(r, 8)).toInt(&ok); if (ok) { entry->setIcon(icon); } + // Modified Time TimeInfo timeInfo; - if (m_parserModel->data(m_parserModel->index(r, 8)).isValid()) { + if (m_parserModel->data(m_parserModel->index(r, 9)).isValid()) { auto datetime = m_parserModel->data(m_parserModel->index(r, 8)).toString(); if (datetime.contains(QRegularExpression("^\\d+$"))) { auto t = datetime.toLongLong(); @@ -272,7 +296,8 @@ QSharedPointer CsvImportWidget::buildDatabase() } } } - if (m_parserModel->data(m_parserModel->index(r, 9)).isValid()) { + // Creation Time + if (m_parserModel->data(m_parserModel->index(r, 10)).isValid()) { auto datetime = m_parserModel->data(m_parserModel->index(r, 9)).toString(); if (datetime.contains(QRegularExpression("^\\d+$"))) { auto t = datetime.toLongLong(); diff --git a/src/gui/csvImport/CsvImportWidget.h b/src/gui/csvImport/CsvImportWidget.h index d5f29c43a..c428d7200 100644 --- a/src/gui/csvImport/CsvImportWidget.h +++ b/src/gui/csvImport/CsvImportWidget.h @@ -1,4 +1,4 @@ -/* +/* * Copyright (C) 2016 Enrico Mariotti * Copyright (C) 2017 KeePassXC Team * diff --git a/src/gui/csvImport/CsvImportWidget.ui b/src/gui/csvImport/CsvImportWidget.ui index cd7af9816..6fb21e595 100644 --- a/src/gui/csvImport/CsvImportWidget.ui +++ b/src/gui/csvImport/CsvImportWidget.ui @@ -40,8 +40,34 @@ Column Association - - + + + + + 200 + 16777215 + + + + QComboBox::AdjustToContents + + + + + + + + 200 + 16777215 + + + + QComboBox::AdjustToContents + + + + + 50 @@ -49,7 +75,215 @@ - Icon + Group + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + + + 2 + + + + + + + + 50 + false + + + + Notes + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + + + 2 + + + + + + + + 50 + false + + + + Username + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + + + 2 + + + + + + + + 200 + 16777215 + + + + QComboBox::AdjustToContents + + + + + + + + 200 + 16777215 + + + + QComboBox::AdjustToContents + + + + + + + + 200 + 16777215 + + + + QComboBox::AdjustToContents + + + + + + + + 50 + false + + + + Last Modified + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + + + 2 + + + + + + + + 200 + 16777215 + + + + QComboBox::AdjustToContents + + + + + + + + 200 + 16777215 + + + + QComboBox::AdjustToContents + + + + + + + + 50 + false + + + + Password + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + + + 2 + + + + + + + Qt::Horizontal + + + QSizePolicy::Fixed + + + + 6 + 20 + + + + + + + + + 50 + false + + + + Created + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + + + 2 + + + + + + + + 200 + 16777215 + + + + QComboBox::AdjustToContents + + + + + + + + 50 + false + + + + URL Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter @@ -78,11 +312,21 @@ - - + + + + + 200 + 16777215 + + + + QComboBox::AdjustToContents + + - - + + 50 @@ -90,7 +334,7 @@ - Notes + Icon Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter @@ -119,178 +363,47 @@ - - - - - - - - - - - - - - - - - 50 - false - - - - First line has field names - - - true - - - - - - - - - - - - - - 50 - false - - - - Password - - - Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter - - - 2 - - - - - - - - 50 - false - - - - Group - - - Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter - - - 2 - - - - - - - - - - - 50 - false - - - - Username - - - Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter - - - 2 - - - - - - - - 50 - false - - - - URL - - - Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter - - - 2 - - - - - - - - - - - 50 - false - - - - Created - - - Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter - - - 2 - - - - - - - - - - 50 - false - - - - Last Modified - - - Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter - - - 2 - - - - - - - Qt::Horizontal - - - QSizePolicy::Fixed - - + + - 6 - 20 + 200 + 16777215 - + + QComboBox::AdjustToContents + + + + + + + + 50 + false + + + + Tags + + + 2 + + + + + + + + 200 + 16777215 + + + + QComboBox::AdjustToContents + + @@ -584,6 +697,22 @@ + + + + + 50 + false + + + + First line has field names + + + true + + + diff --git a/src/gui/csvImport/CsvParserModel.cpp b/src/gui/csvImport/CsvParserModel.cpp index 0ae350817..892b8917b 100644 --- a/src/gui/csvImport/CsvParserModel.cpp +++ b/src/gui/csvImport/CsvParserModel.cpp @@ -30,9 +30,7 @@ CsvParserModel::CsvParserModel(QObject* parent) { } -CsvParserModel::~CsvParserModel() -{ -} +CsvParserModel::~CsvParserModel() = default; CsvParser* CsvParserModel::parser() { @@ -94,6 +92,11 @@ void CsvParserModel::setSkippedRows(int skipped) emit layoutChanged(); } +int CsvParserModel::skippedRows() const +{ + return m_skipped; +} + void CsvParserModel::setHeaderLabels(const QStringList& labels) { m_columnHeader = labels; @@ -126,7 +129,7 @@ QVariant CsvParserModel::data(const QModelIndex& index, int role) const return m_parser->getCsvTable().at(index.row() + m_skipped).at(column); } } - return QVariant(); + return {}; } QVariant CsvParserModel::headerData(int section, Qt::Orientation orientation, int role) const @@ -142,5 +145,5 @@ QVariant CsvParserModel::headerData(int section, Qt::Orientation orientation, in } } } - return QVariant(); + return {}; } diff --git a/src/gui/csvImport/CsvParserModel.h b/src/gui/csvImport/CsvParserModel.h index 2717b826d..d9fb4af46 100644 --- a/src/gui/csvImport/CsvParserModel.h +++ b/src/gui/csvImport/CsvParserModel.h @@ -45,8 +45,8 @@ public: QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override; QVariant headerData(int section, Qt::Orientation orientation, int role) const override; -public slots: void setSkippedRows(int skipped); + int skippedRows() const; private: CsvParser* m_parser; diff --git a/src/gui/databasekey/KeyComponentWidget.cpp b/src/gui/databasekey/KeyComponentWidget.cpp index e0cdc0f8a..1fad34427 100644 --- a/src/gui/databasekey/KeyComponentWidget.cpp +++ b/src/gui/databasekey/KeyComponentWidget.cpp @@ -43,9 +43,7 @@ KeyComponentWidget::KeyComponentWidget(QWidget* parent) m_ui->stackedWidget->blockSignals(prev); } -KeyComponentWidget::~KeyComponentWidget() -{ -} +KeyComponentWidget::~KeyComponentWidget() = default; void KeyComponentWidget::setComponentAdded(bool added) { @@ -75,6 +73,10 @@ KeyComponentWidget::Page KeyComponentWidget::visiblePage() const void KeyComponentWidget::updateAddStatus(bool added) { + if (m_ui->stackedWidget->currentIndex() == Page::Edit) { + emit editCanceled(); + } + if (added) { m_ui->stackedWidget->setCurrentIndex(Page::LeaveOrRemove); } else { @@ -103,12 +105,6 @@ void KeyComponentWidget::cancelEdit() emit editCanceled(); } -void KeyComponentWidget::showEvent(QShowEvent* event) -{ - resetComponentEditWidget(); - QWidget::showEvent(event); -} - void KeyComponentWidget::resetComponentEditWidget() { if (!m_componentWidget || static_cast(m_ui->stackedWidget->currentIndex()) == Page::Edit) { diff --git a/src/gui/databasekey/KeyComponentWidget.h b/src/gui/databasekey/KeyComponentWidget.h index 9ea53da96..d207e494d 100644 --- a/src/gui/databasekey/KeyComponentWidget.h +++ b/src/gui/databasekey/KeyComponentWidget.h @@ -104,9 +104,6 @@ signals: void editCanceled(); void componentRemovalRequested(); -protected: - void showEvent(QShowEvent* event) override; - private slots: void updateAddStatus(bool added); void doAdd(); diff --git a/src/gui/databasekey/KeyFileEditWidget.cpp b/src/gui/databasekey/KeyFileEditWidget.cpp index dc38d05d7..dfaef273c 100644 --- a/src/gui/databasekey/KeyFileEditWidget.cpp +++ b/src/gui/databasekey/KeyFileEditWidget.cpp @@ -33,9 +33,7 @@ KeyFileEditWidget::KeyFileEditWidget(DatabaseSettingsWidget* parent) initComponent(); } -KeyFileEditWidget::~KeyFileEditWidget() -{ -} +KeyFileEditWidget::~KeyFileEditWidget() = default; bool KeyFileEditWidget::addToCompositeKey(QSharedPointer key) { diff --git a/src/gui/databasekey/PasswordEditWidget.cpp b/src/gui/databasekey/PasswordEditWidget.cpp index 647bdc2d2..e04f6e0b1 100644 --- a/src/gui/databasekey/PasswordEditWidget.cpp +++ b/src/gui/databasekey/PasswordEditWidget.cpp @@ -27,11 +27,12 @@ PasswordEditWidget::PasswordEditWidget(QWidget* parent) , m_compUi(new Ui::PasswordEditWidget()) { initComponent(); + + // Explicitly clear password on cancel + connect(this, &PasswordEditWidget::editCanceled, this, [this] { setPassword({}); }); } -PasswordEditWidget::~PasswordEditWidget() -{ -} +PasswordEditWidget::~PasswordEditWidget() = default; bool PasswordEditWidget::addToCompositeKey(QSharedPointer key) { @@ -61,7 +62,7 @@ bool PasswordEditWidget::isPasswordVisible() const bool PasswordEditWidget::isEmpty() const { - return (visiblePage() == Page::Edit) && m_compUi->enterPasswordEdit->text().isEmpty(); + return m_compUi->enterPasswordEdit->text().isEmpty(); } PasswordHealth::Quality PasswordEditWidget::getPasswordQuality() const @@ -85,8 +86,7 @@ void PasswordEditWidget::initComponentEditWidget(QWidget* widget) { Q_UNUSED(widget); Q_ASSERT(m_compEditWidget); - m_compUi->enterPasswordEdit->setFocus(); - + setFocusProxy(m_compUi->enterPasswordEdit); m_compUi->enterPasswordEdit->setQualityVisible(true); m_compUi->repeatPasswordEdit->setQualityVisible(false); } @@ -105,16 +105,6 @@ void PasswordEditWidget::initComponent() "

    Good passwords are long and unique. KeePassXC can generate one for you.

    ")); } -void PasswordEditWidget::hideEvent(QHideEvent* event) -{ - if (!isVisible() && m_compUi->enterPasswordEdit) { - m_compUi->enterPasswordEdit->setText(""); - m_compUi->repeatPasswordEdit->setText(""); - } - - QWidget::hideEvent(event); -} - bool PasswordEditWidget::validate(QString& errorMessage) const { if (m_compUi->enterPasswordEdit->text() != m_compUi->repeatPasswordEdit->text()) { diff --git a/src/gui/databasekey/PasswordEditWidget.h b/src/gui/databasekey/PasswordEditWidget.h index 5e7bb28d6..14dfe1d81 100644 --- a/src/gui/databasekey/PasswordEditWidget.h +++ b/src/gui/databasekey/PasswordEditWidget.h @@ -47,7 +47,6 @@ protected: QWidget* componentEditWidget() override; void initComponentEditWidget(QWidget* widget) override; void initComponent() override; - void hideEvent(QHideEvent* event) override; private slots: void setPassword(const QString& password); diff --git a/src/gui/databasekey/YubiKeyEditWidget.cpp b/src/gui/databasekey/YubiKeyEditWidget.cpp index 857531f73..edac12af0 100644 --- a/src/gui/databasekey/YubiKeyEditWidget.cpp +++ b/src/gui/databasekey/YubiKeyEditWidget.cpp @@ -42,9 +42,7 @@ YubiKeyEditWidget::YubiKeyEditWidget(QWidget* parent) #endif } -YubiKeyEditWidget::~YubiKeyEditWidget() -{ -} +YubiKeyEditWidget::~YubiKeyEditWidget() = default; bool YubiKeyEditWidget::addToCompositeKey(QSharedPointer key) { @@ -141,9 +139,9 @@ void YubiKeyEditWidget::initComponent() m_ui->componentDescription->setText( tr("

    If you own a YubiKey or " "OnlyKey, you can use it for additional security.

    " - "

    The key requires one of its slots to be programmed as " - "" - "HMAC-SHA1 Challenge-Response.

    ")); + "

    The key requires one of its slots to be programmed with " + "" + "Challenge-Response.

    ")); } void YubiKeyEditWidget::pollYubikey() @@ -175,7 +173,9 @@ void YubiKeyEditWidget::hardwareKeyResponse(bool found) if (!found) { m_compUi->yubikeyProgress->setVisible(false); - m_compUi->comboChallengeResponse->addItem(tr("No hardware keys detected")); + m_compUi->comboChallengeResponse->addItem(YubiKey::instance()->connectedKeys() > 0 + ? tr("Hardware keys found, but no slots are configured") + : tr("No hardware keys detected")); m_isDetected = false; return; } diff --git a/src/gui/dbsettings/DatabaseSettingsDialog.cpp b/src/gui/dbsettings/DatabaseSettingsDialog.cpp index 470119b68..fd772c291 100644 --- a/src/gui/dbsettings/DatabaseSettingsDialog.cpp +++ b/src/gui/dbsettings/DatabaseSettingsDialog.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2018 KeePassXC Team + * Copyright (C) 2023 KeePassXC Team * Copyright (C) 2012 Felix Geyer * * This program is free software: you can redistribute it and/or modify @@ -17,20 +17,19 @@ */ #include "DatabaseSettingsDialog.h" -#include "ui_DatabaseSettingsDialog.h" - #include "DatabaseSettingsWidgetDatabaseKey.h" #include "DatabaseSettingsWidgetEncryption.h" #include "DatabaseSettingsWidgetGeneral.h" #ifdef WITH_XC_BROWSER #include "DatabaseSettingsWidgetBrowser.h" #endif +#include "../remote/DatabaseSettingsWidgetRemote.h" #include "DatabaseSettingsWidgetMaintenance.h" #ifdef WITH_XC_KEESHARE -#include "keeshare/DatabaseSettingsPageKeeShare.h" +#include "keeshare/DatabaseSettingsWidgetKeeShare.h" #endif #ifdef WITH_XC_FDOSECRETS -#include "fdosecrets/DatabaseSettingsPageFdoSecrets.h" +#include "fdosecrets/widgets/DatabaseSettingsWidgetFdoSecrets.h" #endif #include "core/Database.h" @@ -39,50 +38,29 @@ #include -class DatabaseSettingsDialog::ExtraPage -{ -public: - ExtraPage(IDatabaseSettingsPage* page, QWidget* widget) - : settingsPage(page) - , widget(widget) - { - } - void loadSettings(QSharedPointer db) const - { - settingsPage->loadSettings(widget, db); - } - void saveSettings() const - { - settingsPage->saveSettings(widget); - } - -private: - QSharedPointer settingsPage; - QWidget* widget; -}; - DatabaseSettingsDialog::DatabaseSettingsDialog(QWidget* parent) - : DialogyWidget(parent) - , m_ui(new Ui::DatabaseSettingsDialog()) + : EditWidget(parent) , m_generalWidget(new DatabaseSettingsWidgetGeneral(this)) , m_securityTabWidget(new QTabWidget(this)) , m_databaseKeyWidget(new DatabaseSettingsWidgetDatabaseKey(this)) , m_encryptionWidget(new DatabaseSettingsWidgetEncryption(this)) #ifdef WITH_XC_BROWSER , m_browserWidget(new DatabaseSettingsWidgetBrowser(this)) +#endif +#ifdef WITH_XC_KEESHARE + , m_keeShareWidget(new DatabaseSettingsWidgetKeeShare(this)) +#endif +#ifdef WITH_XC_FDOSECRETS + , m_fdoSecretsWidget(new DatabaseSettingsWidgetFdoSecrets(this)) #endif , m_maintenanceWidget(new DatabaseSettingsWidgetMaintenance(this)) + , m_remoteWidget(new DatabaseSettingsWidgetRemote(this)) { - m_ui->setupUi(this); + connect(this, SIGNAL(accepted()), SLOT(save())); + connect(this, SIGNAL(rejected()), SLOT(reject())); - connect(m_ui->buttonBox, SIGNAL(accepted()), SLOT(save())); - connect(m_ui->buttonBox, SIGNAL(rejected()), SLOT(reject())); - - m_ui->categoryList->addCategory(tr("General"), icons()->icon("preferences-other")); - m_ui->categoryList->addCategory(tr("Security"), icons()->icon("security-high")); - m_ui->stackedWidget->addWidget(m_generalWidget); - - m_ui->stackedWidget->addWidget(m_securityTabWidget); + addPage(tr("General"), icons()->icon("preferences-other"), m_generalWidget); + addPage(tr("Security"), icons()->icon("security-high"), m_securityTabWidget); auto* scrollArea = new QScrollArea(parent); scrollArea->setFrameShape(QFrame::NoFrame); @@ -91,102 +69,117 @@ DatabaseSettingsDialog::DatabaseSettingsDialog(QWidget* parent) scrollArea->setSizeAdjustPolicy(QScrollArea::AdjustToContents); scrollArea->setWidgetResizable(true); scrollArea->setWidget(m_databaseKeyWidget); - m_securityTabWidget->addTab(scrollArea, tr("Database Credentials")); + m_securityTabWidget->setObjectName("securityTabWidget"); + m_securityTabWidget->addTab(scrollArea, tr("Database Credentials")); m_securityTabWidget->addTab(m_encryptionWidget, tr("Encryption Settings")); -#if defined(WITH_XC_KEESHARE) - addSettingsPage(new DatabaseSettingsPageKeeShare()); -#endif - -#if defined(WITH_XC_FDOSECRETS) - addSettingsPage(new DatabaseSettingsPageFdoSecrets()); -#endif - - m_ui->stackedWidget->setCurrentIndex(0); m_securityTabWidget->setCurrentIndex(0); - connect(m_securityTabWidget, SIGNAL(currentChanged(int)), SLOT(pageChanged())); - connect(m_ui->categoryList, SIGNAL(categoryChanged(int)), m_ui->stackedWidget, SLOT(setCurrentIndex(int))); + addPage(tr("Remote Sync"), icons()->icon("remote-sync"), m_remoteWidget); #ifdef WITH_XC_BROWSER - m_ui->categoryList->addCategory(tr("Browser Integration"), icons()->icon("internet-web-browser")); - m_ui->stackedWidget->addWidget(m_browserWidget); + addPage(tr("Browser Integration"), icons()->icon("internet-web-browser"), m_browserWidget); #endif - m_ui->categoryList->addCategory(tr("Maintenance"), icons()->icon("hammer-wrench")); - m_ui->stackedWidget->addWidget(m_maintenanceWidget); +#ifdef WITH_XC_KEESHARE + addPage(tr("KeeShare"), icons()->icon("preferences-system-network-sharing"), m_keeShareWidget); +#endif - pageChanged(); +#ifdef WITH_XC_FDOSECRETS + addPage(tr("Secret Service Integration"), icons()->icon(QStringLiteral("freedesktop")), m_fdoSecretsWidget); +#endif + + addPage(tr("Maintenance"), icons()->icon("hammer-wrench"), m_maintenanceWidget); + + setCurrentPage(0); } -DatabaseSettingsDialog::~DatabaseSettingsDialog() -{ -} +DatabaseSettingsDialog::~DatabaseSettingsDialog() = default; void DatabaseSettingsDialog::load(const QSharedPointer& db) { - m_ui->categoryList->setCurrentCategory(0); - m_generalWidget->load(db); - m_databaseKeyWidget->load(db); - m_encryptionWidget->load(db); -#ifdef WITH_XC_BROWSER - m_browserWidget->load(db); -#endif - m_maintenanceWidget->load(db); - for (const ExtraPage& page : asConst(m_extraPages)) { - page.loadSettings(db); - } - m_db = db; -} + // Default to the main page on load + setCurrentPage(0); + setHeadline(tr("Database Settings: %1").arg(db->canonicalFilePath())); -void DatabaseSettingsDialog::addSettingsPage(IDatabaseSettingsPage* page) -{ - const int category = m_ui->categoryList->currentCategory(); - QWidget* widget = page->createWidget(); - widget->setParent(this); - m_extraPages.append(ExtraPage(page, widget)); - m_ui->stackedWidget->addWidget(widget); - m_ui->categoryList->addCategory(page->name(), page->icon()); - m_ui->categoryList->setCurrentCategory(category); + m_generalWidget->loadSettings(db); + m_databaseKeyWidget->loadSettings(db); + m_encryptionWidget->loadSettings(db); + m_remoteWidget->loadSettings(db); +#ifdef WITH_XC_BROWSER + m_browserWidget->loadSettings(db); +#endif +#ifdef WITH_XC_KEESHARE + m_keeShareWidget->loadSettings(db); +#endif +#ifdef WITH_XC_FDOSECRETS + m_fdoSecretsWidget->loadSettings(db); +#endif + m_maintenanceWidget->loadSettings(db); + + m_db = db; } /** * Show page and tab with database database key settings. */ -void DatabaseSettingsDialog::showDatabaseKeySettings() +void DatabaseSettingsDialog::showDatabaseKeySettings(int index) { - m_ui->categoryList->setCurrentCategory(1); - m_securityTabWidget->setCurrentIndex(0); + setCurrentPage(1); + m_securityTabWidget->setCurrentIndex(index); +} + +void DatabaseSettingsDialog::showRemoteSettings() +{ + setCurrentPage(2); } void DatabaseSettingsDialog::save() { - if (!m_generalWidget->save()) { + if (!m_generalWidget->saveSettings()) { + setCurrentPage(0); return; } - if (!m_databaseKeyWidget->save()) { + if (!m_databaseKeyWidget->saveSettings()) { + setCurrentPage(1); + m_securityTabWidget->setCurrentIndex(0); return; } - if (!m_encryptionWidget->save()) { + if (!m_encryptionWidget->saveSettings()) { + setCurrentPage(1); + m_securityTabWidget->setCurrentIndex(1); return; } - for (const ExtraPage& extraPage : asConst(m_extraPages)) { - extraPage.saveSettings(); + if (!m_remoteWidget->saveSettings()) { + setCurrentPage(2); + return; } + // Browser settings don't have anything to save + +#ifdef WITH_XC_KEESHARE + m_keeShareWidget->saveSettings(); +#endif +#ifdef WITH_XC_FDOSECRETS + m_fdoSecretsWidget->saveSettings(); +#endif + emit editFinished(true); } void DatabaseSettingsDialog::reject() { + m_generalWidget->discard(); + m_databaseKeyWidget->discard(); + m_encryptionWidget->discard(); + m_remoteWidget->discard(); +#ifdef WITH_XC_BROWSER + m_browserWidget->discard(); +#endif + emit editFinished(false); } - -void DatabaseSettingsDialog::pageChanged() -{ - m_ui->stackedWidget->currentIndex(); -} diff --git a/src/gui/dbsettings/DatabaseSettingsDialog.h b/src/gui/dbsettings/DatabaseSettingsDialog.h index e2b225aff..83bc56abe 100644 --- a/src/gui/dbsettings/DatabaseSettingsDialog.h +++ b/src/gui/dbsettings/DatabaseSettingsDialog.h @@ -1,4 +1,5 @@ /* + * Copyright (C) 2023 KeePassXC Team * Copyright (C) 2012 Felix Geyer * * This program is free software: you can redistribute it and/or modify @@ -15,11 +16,11 @@ * along with this program. If not, see . */ -#ifndef KEEPASSX_DATABASESETTINGSWIDGET_H -#define KEEPASSX_DATABASESETTINGSWIDGET_H +#ifndef KEEPASSXC_DATABASESETTINGSDIALOG_H +#define KEEPASSXC_DATABASESETTINGSDIALOG_H #include "config-keepassx.h" -#include "gui/DialogyWidget.h" +#include "gui/EditWidget.h" #include @@ -30,28 +31,17 @@ class DatabaseSettingsWidgetDatabaseKey; #ifdef WITH_XC_BROWSER class DatabaseSettingsWidgetBrowser; #endif +#ifdef WITH_XC_KEESHARE +class DatabaseSettingsWidgetKeeShare; +#endif +#ifdef WITH_XC_FDOSECRETS +class DatabaseSettingsWidgetFdoSecrets; +#endif class DatabaseSettingsWidgetMaintenance; +class DatabaseSettingsWidgetRemote; class QTabWidget; -namespace Ui -{ - class DatabaseSettingsDialog; -} - -class IDatabaseSettingsPage -{ -public: - virtual ~IDatabaseSettingsPage() - { - } - virtual QString name() = 0; - virtual QIcon icon() = 0; - virtual QWidget* createWidget() = 0; - virtual void loadSettings(QWidget* widget, QSharedPointer db) = 0; - virtual void saveSettings(QWidget* widget) = 0; -}; - -class DatabaseSettingsDialog : public DialogyWidget +class DatabaseSettingsDialog : public EditWidget { Q_OBJECT @@ -61,8 +51,8 @@ public: Q_DISABLE_COPY(DatabaseSettingsDialog); void load(const QSharedPointer& db); - void addSettingsPage(IDatabaseSettingsPage* page); - void showDatabaseKeySettings(); + void showDatabaseKeySettings(int index = 0); + void showRemoteSettings(); signals: void editFinished(bool accepted); @@ -70,28 +60,24 @@ signals: private slots: void save(); void reject(); - void pageChanged(); private: - enum Page - { - General = 0, - Security = 1 - }; - QSharedPointer m_db; - const QScopedPointer m_ui; QPointer m_generalWidget; QPointer m_securityTabWidget; QPointer m_databaseKeyWidget; QPointer m_encryptionWidget; #ifdef WITH_XC_BROWSER QPointer m_browserWidget; +#endif +#ifdef WITH_XC_KEESHARE + QPointer m_keeShareWidget; +#endif +#ifdef WITH_XC_FDOSECRETS + QPointer m_fdoSecretsWidget; #endif QPointer m_maintenanceWidget; - - class ExtraPage; - QList m_extraPages; + QPointer m_remoteWidget; }; -#endif // KEEPASSX_DATABASESETTINGSWIDGET_H +#endif // KEEPASSXC_DATABASESETTINGSDIALOG_H diff --git a/src/gui/dbsettings/DatabaseSettingsDialog.ui b/src/gui/dbsettings/DatabaseSettingsDialog.ui deleted file mode 100644 index 16d46646d..000000000 --- a/src/gui/dbsettings/DatabaseSettingsDialog.ui +++ /dev/null @@ -1,39 +0,0 @@ - - - DatabaseSettingsDialog - - - - - - - - - - - -1 - - - - - - - - - QDialogButtonBox::Cancel|QDialogButtonBox::Ok - - - - - - - - CategoryListWidget - QWidget -
    gui/CategoryListWidget.h
    - 1 -
    -
    - - -
    diff --git a/src/gui/dbsettings/DatabaseSettingsWidget.cpp b/src/gui/dbsettings/DatabaseSettingsWidget.cpp index b2536f203..99d6fff11 100644 --- a/src/gui/dbsettings/DatabaseSettingsWidget.cpp +++ b/src/gui/dbsettings/DatabaseSettingsWidget.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2018 KeePassXC Team + * Copyright (C) 2023 KeePassXC Team * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -23,9 +23,7 @@ DatabaseSettingsWidget::DatabaseSettingsWidget(QWidget* parent) { } -DatabaseSettingsWidget::~DatabaseSettingsWidget() -{ -} +DatabaseSettingsWidget::~DatabaseSettingsWidget() = default; /** * Load the database to be configured by this page and initialize the page. @@ -33,7 +31,7 @@ DatabaseSettingsWidget::~DatabaseSettingsWidget() * * @param db database object to be configured */ -void DatabaseSettingsWidget::load(QSharedPointer db) +void DatabaseSettingsWidget::loadSettings(QSharedPointer db) { m_db = std::move(db); initialize(); diff --git a/src/gui/dbsettings/DatabaseSettingsWidget.h b/src/gui/dbsettings/DatabaseSettingsWidget.h index 243245138..89c048a8d 100644 --- a/src/gui/dbsettings/DatabaseSettingsWidget.h +++ b/src/gui/dbsettings/DatabaseSettingsWidget.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2018 KeePassXC Team + * Copyright (C) 2023 KeePassXC Team * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -18,7 +18,7 @@ #ifndef KEEPASSXC_DATABASESETTINGSWIDGET_H #define KEEPASSXC_DATABASESETTINGSWIDGET_H -#include "gui/settings/SettingsWidget.h" +#include "gui/SettingsWidget.h" class Database; @@ -34,7 +34,7 @@ public: Q_DISABLE_COPY(DatabaseSettingsWidget); ~DatabaseSettingsWidget() override; - virtual void load(QSharedPointer db); + virtual void loadSettings(QSharedPointer db); const QSharedPointer getDatabase() const; diff --git a/src/gui/dbsettings/DatabaseSettingsWidgetBrowser.cpp b/src/gui/dbsettings/DatabaseSettingsWidgetBrowser.cpp index aaa2aff6e..fa52c8b8f 100644 --- a/src/gui/dbsettings/DatabaseSettingsWidgetBrowser.cpp +++ b/src/gui/dbsettings/DatabaseSettingsWidgetBrowser.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2018 KeePassXC Team + * Copyright (C) 2024 KeePassXC Team * Copyright (C) 2018 Sami Vänttinen * * This program is free software: you can redistribute it and/or modify @@ -48,8 +48,6 @@ DatabaseSettingsWidgetBrowser::DatabaseSettingsWidgetBrowser(QWidget* parent) // clang-format on connect(m_ui->removeCustomDataButton, SIGNAL(clicked()), SLOT(removeSelectedKey())); - connect(m_ui->convertToCustomData, SIGNAL(clicked()), this, SLOT(convertAttributesToCustomData())); - connect(m_ui->convertToCustomData, SIGNAL(clicked()), this, SLOT(updateSharedKeyList())); connect(m_ui->removeSharedEncryptionKeys, SIGNAL(clicked()), this, SLOT(removeSharedEncryptionKeys())); connect(m_ui->removeSharedEncryptionKeys, SIGNAL(clicked()), this, SLOT(updateSharedKeyList())); connect(m_ui->removeStoredPermissions, SIGNAL(clicked()), this, SLOT(removeStoredPermissions())); @@ -84,7 +82,7 @@ void DatabaseSettingsWidgetBrowser::showEvent(QShowEvent* event) QWidget::showEvent(event); } -bool DatabaseSettingsWidgetBrowser::save() +bool DatabaseSettingsWidgetBrowser::saveSettings() { return true; } @@ -104,9 +102,10 @@ void DatabaseSettingsWidgetBrowser::removeSelectedKey() const QItemSelectionModel* itemSelectionModel = m_ui->customDataTable->selectionModel(); if (itemSelectionModel) { for (const QModelIndex& index : itemSelectionModel->selectedRows(0)) { - QString key = index.data().toString(); - key.insert(0, CustomData::BrowserKeyPrefix); + const auto key = CustomData::getKeyWithPrefix(CustomData::BrowserKeyPrefix, index.data().toString()); + const auto createdKey = CustomData::getKeyWithPrefix(CustomData::Created, index.data().toString()); customData()->remove(key); + customData()->remove(createdKey); } updateModel(); } @@ -126,7 +125,7 @@ void DatabaseSettingsWidgetBrowser::updateModel() if (key.startsWith(CustomData::BrowserKeyPrefix)) { QString strippedKey = key; strippedKey.remove(CustomData::BrowserKeyPrefix); - auto created = customData()->value(QString("%1_%2").arg(CustomData::Created, strippedKey)); + auto created = customData()->value(CustomData::getKeyWithPrefix(CustomData::Created, strippedKey)); auto createdItem = new QStandardItem(created); createdItem->setEditable(false); m_customDataModel->appendRow(QList() @@ -141,7 +140,6 @@ void DatabaseSettingsWidgetBrowser::updateModel() void DatabaseSettingsWidgetBrowser::settingsWarning() { if (!browserSettings()->isEnabled()) { - m_ui->convertToCustomData->setEnabled(false); m_ui->removeSharedEncryptionKeys->setEnabled(false); m_ui->removeStoredPermissions->setEnabled(false); m_ui->customDataTable->setEnabled(false); @@ -150,7 +148,6 @@ void DatabaseSettingsWidgetBrowser::settingsWarning() m_ui->warningWidget->setCloseButtonVisible(false); m_ui->warningWidget->setAutoHideTimeout(-1); } else { - m_ui->convertToCustomData->setEnabled(true); m_ui->removeSharedEncryptionKeys->setEnabled(true); m_ui->removeStoredPermissions->setEnabled(true); m_ui->customDataTable->setEnabled(true); @@ -218,9 +215,7 @@ void DatabaseSettingsWidgetBrowser::removeStoredPermissions() } if (entry->customData()->contains(BrowserService::KEEPASSXCBROWSER_NAME)) { - entry->beginUpdate(); - entry->customData()->remove(BrowserService::KEEPASSXCBROWSER_NAME); - entry->endUpdate(); + browserService()->removePluginData(entry); ++counter; } progress.setValue(progress.value() + 1); @@ -240,22 +235,6 @@ void DatabaseSettingsWidgetBrowser::removeStoredPermissions() } } -void DatabaseSettingsWidgetBrowser::convertAttributesToCustomData() -{ - if (MessageBox::Yes - != MessageBox::question( - this, - tr("Move KeePassHTTP attributes to custom data"), - tr("Do you really want to convert all legacy browser integration data to the latest standard?\n" - "This is necessary to maintain compatibility with the browser plugin."), - MessageBox::Yes | MessageBox::Cancel, - MessageBox::Cancel)) { - return; - } - - BrowserService::convertAttributesToCustomData(m_db); -} - void DatabaseSettingsWidgetBrowser::refreshDatabaseID() { if (MessageBox::Yes @@ -289,18 +268,16 @@ void DatabaseSettingsWidgetBrowser::editFinished(QStandardItem* item) if (itemSelectionModel) { auto indexList = itemSelectionModel->selectedRows(item->column()); - if (indexList.length() > 0) { - QString newValue = item->index().data().toString(); + if (!indexList.isEmpty()) { + auto newValue = item->index().data().toString(); // The key is edited if (item->column() == 0) { - // Get the old key/value pair, remove it and replace it - m_valueInEdit.insert(0, CustomData::BrowserKeyPrefix); - auto tempValue = customData()->value(m_valueInEdit); - newValue.insert(0, CustomData::BrowserKeyPrefix); + // Update created timestamp with the new key + replaceKey(CustomData::Created, m_valueInEdit, newValue); - m_db->metadata()->customData()->remove(m_valueInEdit); - m_db->metadata()->customData()->set(newValue, tempValue); + // Get the old key/value pair, remove it and replace it + replaceKey(CustomData::BrowserKeyPrefix, m_valueInEdit, newValue); } else { // Replace just the value for (const QString& key : m_db->metadata()->customData()->keys()) { @@ -323,3 +300,15 @@ void DatabaseSettingsWidgetBrowser::updateSharedKeyList() { updateModel(); } + +// Replaces a key and the created timestamp for it +void DatabaseSettingsWidgetBrowser::replaceKey(const QString& prefix, + const QString& oldName, + const QString& newName) const +{ + const auto oldKey = CustomData::getKeyWithPrefix(prefix, oldName); + const auto newKey = CustomData::getKeyWithPrefix(prefix, newName); + const auto tempValue = customData()->value(oldKey); + m_db->metadata()->customData()->remove(oldKey); + m_db->metadata()->customData()->set(newKey, tempValue); +} diff --git a/src/gui/dbsettings/DatabaseSettingsWidgetBrowser.h b/src/gui/dbsettings/DatabaseSettingsWidgetBrowser.h index 032b3b273..25664a71f 100644 --- a/src/gui/dbsettings/DatabaseSettingsWidgetBrowser.h +++ b/src/gui/dbsettings/DatabaseSettingsWidgetBrowser.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2018 KeePassXC Team + * Copyright (C) 2024 KeePassXC Team * Copyright (C) 2018 Sami Vänttinen * * This program is free software: you can redistribute it and/or modify @@ -47,7 +47,7 @@ public: public slots: void initialize() override; void uninitialize() override; - bool save() override; + bool saveSettings() override; private slots: void removeSelectedKey(); @@ -55,7 +55,6 @@ private slots: void updateSharedKeyList(); void removeSharedEncryptionKeys(); void removeStoredPermissions(); - void convertAttributesToCustomData(); void refreshDatabaseID(); void editIndex(const QModelIndex& index); void editFinished(QStandardItem* item); @@ -63,6 +62,7 @@ private slots: private: void updateModel(); void settingsWarning(); + void replaceKey(const QString& prefix, const QString& oldName, const QString& newName) const; protected: void showEvent(QShowEvent* event) override; diff --git a/src/gui/dbsettings/DatabaseSettingsWidgetBrowser.ui b/src/gui/dbsettings/DatabaseSettingsWidgetBrowser.ui index f33421075..d323e2b47 100644 --- a/src/gui/dbsettings/DatabaseSettingsWidgetBrowser.ui +++ b/src/gui/dbsettings/DatabaseSettingsWidgetBrowser.ui @@ -54,35 +54,6 @@ KeePassXC-Browser settings - - - - - 0 - 0 - - - - Convert KeePassHTTP data - - - Convert legacy KeePassHTTP attributes to KeePassXC-Browser compatible custom data - - - - - - - - 0 - 0 - - - - Refresh database root group ID - - - @@ -112,6 +83,19 @@ + + + + + 0 + 0 + + + + Refresh database root group ID + + + @@ -192,7 +176,6 @@ removeSharedEncryptionKeys removeStoredPermissions - convertToCustomData refreshDatabaseID customDataTable removeCustomDataButton diff --git a/src/gui/dbsettings/DatabaseSettingsWidgetDatabaseKey.cpp b/src/gui/dbsettings/DatabaseSettingsWidgetDatabaseKey.cpp index 552098227..a74b20ead 100644 --- a/src/gui/dbsettings/DatabaseSettingsWidgetDatabaseKey.cpp +++ b/src/gui/dbsettings/DatabaseSettingsWidgetDatabaseKey.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2018 KeePassXC Team + * Copyright (C) 2023 KeePassXC Team * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -27,13 +27,7 @@ #include "keys/ChallengeResponseKey.h" #include "keys/FileKey.h" #include "keys/PasswordKey.h" - -#ifdef Q_OS_MACOS -#include "touchid/TouchID.h" -#endif -#ifdef Q_CC_MSVC -#include "winhello/WindowsHello.h" -#endif +#include "quickunlock/QuickUnlockInterface.h" #include #include @@ -52,10 +46,10 @@ DatabaseSettingsWidgetDatabaseKey::DatabaseSettingsWidgetDatabaseKey(QWidget* pa vbox->setSizeConstraint(QLayout::SetMinimumSize); vbox->setSpacing(20); - // primary password option + // Primary password option vbox->addWidget(m_passwordEditWidget); - // additional key options + // Additional key options m_additionalKeyOptionsToggle->setObjectName("additionalKeyOptionsToggle"); vbox->addWidget(m_additionalKeyOptionsToggle); vbox->addWidget(m_additionalKeyOptions); @@ -75,40 +69,39 @@ DatabaseSettingsWidgetDatabaseKey::DatabaseSettingsWidgetDatabaseKey(QWidget* pa setLayout(vbox); } -DatabaseSettingsWidgetDatabaseKey::~DatabaseSettingsWidgetDatabaseKey() -{ -} +DatabaseSettingsWidgetDatabaseKey::~DatabaseSettingsWidgetDatabaseKey() = default; -void DatabaseSettingsWidgetDatabaseKey::load(QSharedPointer db) +void DatabaseSettingsWidgetDatabaseKey::loadSettings(QSharedPointer db) { - DatabaseSettingsWidget::load(db); + DatabaseSettingsWidget::loadSettings(db); if (!m_db->key() || m_db->key()->keys().isEmpty()) { - // database has no key, we are about to add a new one + // Database has no key, we are about to add a new one m_passwordEditWidget->changeVisiblePage(KeyComponentWidget::Page::Edit); - m_passwordEditWidget->setPasswordVisible(true); - } - - bool hasAdditionalKeys = false; - for (const auto& key : m_db->key()->keys()) { - if (key->uuid() == PasswordKey::UUID) { - m_passwordEditWidget->setComponentAdded(true); - } else if (key->uuid() == FileKey::UUID) { - m_keyFileEditWidget->setComponentAdded(true); - hasAdditionalKeys = true; + // Focus won't work until the UI settles + QTimer::singleShot(0, m_passwordEditWidget, SLOT(setFocus())); + } else { + bool hasAdditionalKeys = false; + for (const auto& key : m_db->key()->keys()) { + if (key->uuid() == PasswordKey::UUID) { + m_passwordEditWidget->setComponentAdded(true); + } else if (key->uuid() == FileKey::UUID) { + m_keyFileEditWidget->setComponentAdded(true); + hasAdditionalKeys = true; + } } - } #ifdef WITH_XC_YUBIKEY - for (const auto& key : m_db->key()->challengeResponseKeys()) { - if (key->uuid() == ChallengeResponseKey::UUID) { - m_yubiKeyEditWidget->setComponentAdded(true); - hasAdditionalKeys = true; + for (const auto& key : m_db->key()->challengeResponseKeys()) { + if (key->uuid() == ChallengeResponseKey::UUID) { + m_yubiKeyEditWidget->setComponentAdded(true); + hasAdditionalKeys = true; + } } - } #endif - setAdditionalKeyOptionsVisible(hasAdditionalKeys); + setAdditionalKeyOptionsVisible(hasAdditionalKeys); + } connect(m_passwordEditWidget->findChild("removeButton"), SIGNAL(clicked()), SLOT(markDirty())); connect(m_keyFileEditWidget->findChild("removeButton"), SIGNAL(clicked()), SLOT(markDirty())); @@ -132,7 +125,7 @@ void DatabaseSettingsWidgetDatabaseKey::uninitialize() { } -bool DatabaseSettingsWidgetDatabaseKey::save() +bool DatabaseSettingsWidgetDatabaseKey::saveSettings() { m_isDirty |= (m_passwordEditWidget->visiblePage() == KeyComponentWidget::Page::Edit); m_isDirty |= (m_keyFileEditWidget->visiblePage() == KeyComponentWidget::Page::Edit); @@ -141,7 +134,7 @@ bool DatabaseSettingsWidgetDatabaseKey::save() #endif if (m_db->key() && !m_db->key()->keys().isEmpty() && !m_isDirty) { - // key unchanged + // Key unchanged return true; } @@ -166,7 +159,9 @@ bool DatabaseSettingsWidgetDatabaseKey::save() } // Show warning if database password has not been set - if (m_passwordEditWidget->visiblePage() == KeyComponentWidget::Page::AddNew || m_passwordEditWidget->isEmpty()) { + if (m_passwordEditWidget->visiblePage() == KeyComponentWidget::Page::AddNew + || (m_passwordEditWidget->visiblePage() == KeyComponentWidget::Page::Edit && m_passwordEditWidget->isEmpty())) { + QScopedPointer msgBox(new QMessageBox(this)); msgBox->setIcon(QMessageBox::Warning); msgBox->setWindowTitle(tr("No password set")); @@ -185,31 +180,32 @@ bool DatabaseSettingsWidgetDatabaseKey::save() return false; } - // Show warning if database password is weak - if (!m_passwordEditWidget->isEmpty() - && m_passwordEditWidget->getPasswordQuality() < PasswordHealth::Quality::Good) { - auto dialogResult = MessageBox::warning(this, - tr("Weak password"), - tr("This is a weak password! For better protection of your secrets, " - "you should choose a stronger password."), - MessageBox::ContinueWithWeakPass | MessageBox::Cancel, - MessageBox::Cancel); - - if (dialogResult == MessageBox::Cancel) { + if (m_passwordEditWidget->visiblePage() == KeyComponentWidget::Page::Edit && !m_passwordEditWidget->isEmpty()) { + // Prevent setting password with a quality less than the minimum required + auto minQuality = qBound(0, config()->get(Config::Security_DatabasePasswordMinimumQuality).toInt(), 4); + if (m_passwordEditWidget->getPasswordQuality() < static_cast(minQuality)) { + MessageBox::critical(this, + tr("Weak password"), + tr("The provided password does not meet the minimum quality requirement."), + MessageBox::Ok, + MessageBox::Ok); return false; } - } - // If enforced in the config file, deny users from continuing with a weak password - auto minQuality = - static_cast(config()->get(Config::Security_DatabasePasswordMinimumQuality).toInt()); - if (!m_passwordEditWidget->isEmpty() && m_passwordEditWidget->getPasswordQuality() < minQuality) { - MessageBox::critical(this, - tr("Weak password"), - tr("You must enter a stronger password to protect your database."), - MessageBox::Ok, - MessageBox::Ok); - return false; + // Show warning if database password is weak or poor + if (m_passwordEditWidget->getPasswordQuality() < PasswordHealth::Quality::Good) { + auto dialogResult = + MessageBox::warning(this, + tr("Weak password"), + tr("This is a weak password! For better protection of your secrets, " + "you should choose a stronger password."), + MessageBox::ContinueWithWeakPass | MessageBox::Cancel, + MessageBox::Cancel); + + if (dialogResult == MessageBox::Cancel) { + return false; + } + } } if (!addToCompositeKey(m_keyFileEditWidget, newKey, oldFileKey)) { @@ -233,22 +229,23 @@ bool DatabaseSettingsWidgetDatabaseKey::save() m_db->setKey(newKey, true, false, false); -#if defined(Q_OS_MACOS) - TouchID::getInstance().reset(m_db->filePath()); -#elif defined(Q_CC_MSVC) - getWindowsHello()->reset(m_db->filePath()); -#endif + getQuickUnlock()->reset(m_db->publicUuid()); emit editFinished(true); if (m_isDirty) { m_db->markAsModified(); } + // Reset fields + initialize(); + return true; } void DatabaseSettingsWidgetDatabaseKey::discard() { + // Reset fields + initialize(); emit editFinished(false); } diff --git a/src/gui/dbsettings/DatabaseSettingsWidgetDatabaseKey.h b/src/gui/dbsettings/DatabaseSettingsWidgetDatabaseKey.h index 258f33e36..3e4bcdc73 100644 --- a/src/gui/dbsettings/DatabaseSettingsWidgetDatabaseKey.h +++ b/src/gui/dbsettings/DatabaseSettingsWidgetDatabaseKey.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2018 KeePassXC Team + * Copyright (C) 2023 KeePassXC Team * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -15,8 +15,8 @@ * along with this program. If not, see . */ -#ifndef KEEPASSXC_DATABASESETTINGSPAGECHANGEDBKEY_H -#define KEEPASSXC_DATABASESETTINGSPAGECHANGEDBKEY_H +#ifndef KEEPASSXC_DATABASESETTINGSWIDGETDATABASEKEY_H +#define KEEPASSXC_DATABASESETTINGSWIDGETDATABASEKEY_H #include "DatabaseSettingsWidget.h" #include "config-keepassx.h" @@ -42,12 +42,12 @@ public: Q_DISABLE_COPY(DatabaseSettingsWidgetDatabaseKey); ~DatabaseSettingsWidgetDatabaseKey() override; - void load(QSharedPointer db) override; + void loadSettings(QSharedPointer db) override; public slots: void initialize() override; void uninitialize() override; - bool save() override; + bool saveSettings() override; void discard() override; private slots: @@ -77,4 +77,4 @@ private: #endif }; -#endif // KEEPASSXC_DATABASESETTINGSPAGECHANGEDBKEY_H +#endif // KEEPASSXC_DATABASESETTINGSWIDGETDATABASEKEY_H diff --git a/src/gui/dbsettings/DatabaseSettingsWidgetEncryption.cpp b/src/gui/dbsettings/DatabaseSettingsWidgetEncryption.cpp index 2cc21da1e..7ccf6bc57 100644 --- a/src/gui/dbsettings/DatabaseSettingsWidgetEncryption.cpp +++ b/src/gui/dbsettings/DatabaseSettingsWidgetEncryption.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2018 KeePassXC Team + * Copyright (C) 2023 KeePassXC Team * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -52,14 +52,15 @@ DatabaseSettingsWidgetEncryption::DatabaseSettingsWidgetEncryption(QWidget* pare m_ui->setupUi(this); connect(m_ui->transformBenchmarkButton, SIGNAL(clicked()), SLOT(benchmarkTransformRounds())); - connect(m_ui->kdfComboBox, SIGNAL(currentIndexChanged(int)), SLOT(changeKdf(int))); + connect(m_ui->kdfComboBox, SIGNAL(currentIndexChanged(int)), SLOT(updateKdfFields())); + connect(m_ui->compatibilitySelection, SIGNAL(currentIndexChanged(int)), SLOT(loadKdfAlgorithms())); m_ui->formatCannotBeChanged->setVisible(false); connect(m_ui->memorySpinBox, SIGNAL(valueChanged(int)), this, SLOT(memoryChanged(int))); connect(m_ui->parallelismSpinBox, SIGNAL(valueChanged(int)), this, SLOT(parallelismChanged(int))); - m_ui->compatibilitySelection->addItem(tr("KDBX 4 (recommended)"), KeePass2::KDF_ARGON2D.toByteArray()); - m_ui->compatibilitySelection->addItem(tr("KDBX 3"), KeePass2::KDF_AES_KDBX3.toByteArray()); + m_ui->compatibilitySelection->addItem(tr("KDBX 4 (recommended)"), KeePass2::KDF_ARGON2D); + m_ui->compatibilitySelection->addItem(tr("KDBX 3"), KeePass2::KDF_AES_KDBX3); m_ui->decryptionTimeSlider->setMinimum(Kdf::MIN_ENCRYPTION_TIME / 100); m_ui->decryptionTimeSlider->setMaximum(Kdf::MAX_ENCRYPTION_TIME / 100); m_ui->decryptionTimeSlider->setValue(Kdf::DEFAULT_ENCRYPTION_TIME / 100); @@ -71,9 +72,8 @@ DatabaseSettingsWidgetEncryption::DatabaseSettingsWidgetEncryption(QWidget* pare m_ui->maxTimeLabel->setText(getTextualEncryptionTime(Kdf::MAX_ENCRYPTION_TIME)); connect(m_ui->decryptionTimeSlider, SIGNAL(valueChanged(int)), SLOT(updateDecryptionTime(int))); - connect(m_ui->compatibilitySelection, SIGNAL(currentIndexChanged(int)), SLOT(updateFormatCompatibility(int))); - // conditions under which a key re-transformation is needed + // Conditions under which a key re-transformation is needed connect(m_ui->decryptionTimeSlider, SIGNAL(valueChanged(int)), SLOT(markDirty())); connect(m_ui->compatibilitySelection, SIGNAL(currentIndexChanged(int)), SLOT(markDirty())); connect(m_ui->algorithmComboBox, SIGNAL(currentIndexChanged(int)), SLOT(markDirty())); @@ -83,9 +83,7 @@ DatabaseSettingsWidgetEncryption::DatabaseSettingsWidgetEncryption(QWidget* pare connect(m_ui->parallelismSpinBox, SIGNAL(valueChanged(int)), SLOT(markDirty())); } -DatabaseSettingsWidgetEncryption::~DatabaseSettingsWidgetEncryption() -{ -} +DatabaseSettingsWidgetEncryption::~DatabaseSettingsWidgetEncryption() = default; void DatabaseSettingsWidgetEncryption::showBasicEncryption(int decryptionMillisecs) { @@ -102,14 +100,9 @@ void DatabaseSettingsWidgetEncryption::initialize() return; } - auto version = KDBX4; - if (m_db->key() && m_db->kdf()) { - version = (m_db->kdf()->uuid() == KeePass2::KDF_AES_KDBX3) ? KDBX3 : KDBX4; - } - m_ui->compatibilitySelection->setCurrentIndex(version); - bool isNewDatabase = false; + // Check for uninitialized database parameters and set initial values accordingly if (!m_db->key()) { m_db->setKey(QSharedPointer::create(), true, false, false); m_db->setKdf(KeePass2::uuidToKdf(KeePass2::KDF_ARGON2D)); @@ -120,12 +113,11 @@ void DatabaseSettingsWidgetEncryption::initialize() isNewDatabase = true; } - bool kdbx3Enabled = KeePass2Writer::kdbxVersionRequired(m_db.data(), true, true) <= KeePass2::FILE_VERSION_3_1; + // Initialize the basic settings tab // check if the DB's custom data has a decryption time setting stored // and set the slider to it, otherwise just state that the time is unchanged // (we cannot infer the time from the raw KDF settings) - auto* cd = m_db->metadata()->customData(); if (cd->hasKey(CD_DECRYPTION_TIME_PREFERENCE_KEY)) { int decryptionTime = qMax(100, cd->value(CD_DECRYPTION_TIME_PREFERENCE_KEY).toInt()); @@ -140,16 +132,38 @@ void DatabaseSettingsWidgetEncryption::initialize() m_initWithAdvanced = true; } - updateFormatCompatibility(m_db->kdf()->uuid() == KeePass2::KDF_AES_KDBX3 ? KDBX3 : KDBX4, isNewDatabase); - setupAlgorithmComboBox(); - setupKdfComboBox(kdbx3Enabled); - loadKdfParameters(); + // Initialize the advanced settings tab - if (!kdbx3Enabled) { + // Set up the KDBX version selector + bool isKdbx3 = m_db->formatVersion() <= KeePass2::FILE_VERSION_3_1; + m_ui->compatibilitySelection->blockSignals(true); + m_ui->compatibilitySelection->setCurrentIndex(isKdbx3 ? KDBX3 : KDBX4); + m_ui->compatibilitySelection->blockSignals(false); + + // Disable KDBX selector if downgrading would lose data + if (!isKdbx3 && KeePass2Writer::kdbxVersionRequired(m_db.data(), true, true) >= KeePass2::FILE_VERSION_4) { m_ui->compatibilitySelection->setEnabled(false); m_ui->formatCannotBeChanged->setVisible(true); } + // Set up encryption ciphers + m_ui->algorithmComboBox->clear(); + for (auto& cipher : asConst(KeePass2::CIPHERS)) { + m_ui->algorithmComboBox->addItem(KeePass2::cipherToString(cipher), cipher); + } + int cipherIndex = m_ui->algorithmComboBox->findData(m_db->cipher()); + if (cipherIndex > -1) { + m_ui->algorithmComboBox->setCurrentIndex(cipherIndex); + } + + // Set up KDF algorithms + loadKdfAlgorithms(); + + if (isNewDatabase) { + benchmarkTransformRounds(); + } + + // New databases always require saving m_isDirty = isNewDatabase; } @@ -160,37 +174,36 @@ void DatabaseSettingsWidgetEncryption::uninitialize() void DatabaseSettingsWidgetEncryption::showEvent(QShowEvent* event) { QWidget::showEvent(event); - m_ui->decryptionTimeSlider->setFocus(); -} -void DatabaseSettingsWidgetEncryption::setupAlgorithmComboBox() -{ - m_ui->algorithmComboBox->clear(); - for (auto& cipher : asConst(KeePass2::CIPHERS)) { - m_ui->algorithmComboBox->addItem(KeePass2::cipherToString(cipher), cipher.toByteArray()); - } - int cipherIndex = m_ui->algorithmComboBox->findData(m_db->cipher().toByteArray()); - if (cipherIndex > -1) { - m_ui->algorithmComboBox->setCurrentIndex(cipherIndex); + if (m_ui->decryptionTimeSlider->isVisible()) { + m_ui->decryptionTimeSlider->setFocus(); + } else { + m_ui->transformRoundsSpinBox->setFocus(); } } -void DatabaseSettingsWidgetEncryption::setupKdfComboBox(bool enableKdbx3) +void DatabaseSettingsWidgetEncryption::loadKdfAlgorithms() { - // Set up kdf combo box - bool block = m_ui->kdfComboBox->blockSignals(true); + bool isKdbx3 = m_ui->compatibilitySelection->currentIndex() == KDBX3; + + m_ui->kdfComboBox->blockSignals(true); m_ui->kdfComboBox->clear(); - for (auto& kdf : asConst(KeePass2::KDFS)) { - if (kdf != KeePass2::KDF_AES_KDBX3 or enableKdbx3) { - m_ui->kdfComboBox->addItem(KeePass2::kdfToString(kdf), kdf.toByteArray()); + const auto& kdfs = isKdbx3 ? KeePass2::KDBX3_KDFS : KeePass2::KDBX4_KDFS; + for (auto& kdf : kdfs) { + m_ui->kdfComboBox->addItem(KeePass2::kdfToString(kdf), kdf); + // Set current index to the current database KDF if it matches + if (m_db && m_db->kdf() && m_db->kdf()->uuid() == kdf) { + m_ui->kdfComboBox->setCurrentIndex(m_ui->kdfComboBox->count() - 1); } } - m_ui->kdfComboBox->blockSignals(block); + m_ui->kdfComboBox->blockSignals(false); + + // Ensure consistency with current index + updateKdfFields(); } void DatabaseSettingsWidgetEncryption::loadKdfParameters() { - Q_ASSERT(m_db); if (!m_db) { return; } @@ -200,31 +213,37 @@ void DatabaseSettingsWidgetEncryption::loadKdfParameters() return; } - int kdfIndex = m_ui->kdfComboBox->findData(m_db->kdf()->uuid().toByteArray()); - if (kdfIndex > -1) { - bool block = m_ui->kdfComboBox->blockSignals(true); - m_ui->kdfComboBox->setCurrentIndex(kdfIndex); - m_ui->kdfComboBox->blockSignals(block); - } - - m_ui->transformRoundsSpinBox->setValue(kdf->rounds()); - if (IS_ARGON2(m_db->kdf()->uuid())) { + // Load database KDF parameters if equal to current choice + bool dbIsArgon2 = IS_ARGON2(kdf->uuid()); + bool kdfIsArgon2 = IS_ARGON2(m_ui->kdfComboBox->currentData().toUuid()); + if (dbIsArgon2 && kdfIsArgon2) { + // Set Argon2 parameters auto argon2Kdf = kdf.staticCast(); - m_ui->memorySpinBox->setValue(static_cast(argon2Kdf->memory()) / (1 << 10)); + m_ui->transformRoundsSpinBox->setValue(argon2Kdf->rounds()); + m_ui->memorySpinBox->setValue(Argon2Kdf::toMebibytes(argon2Kdf->memory())); m_ui->parallelismSpinBox->setValue(argon2Kdf->parallelism()); + } else if (!dbIsArgon2 && !kdfIsArgon2) { + // Set AES KDF parameters + m_ui->transformRoundsSpinBox->setValue(kdf->rounds()); + } else { + // Set reasonable defaults and then benchmark + if (kdfIsArgon2) { + m_ui->memorySpinBox->setValue(Argon2Kdf::toMebibytes(ARGON2_DEFAULT_MEMORY)); + m_ui->parallelismSpinBox->setValue(ARGON2_DEFAULT_PARALLELISM); + } + benchmarkTransformRounds(); } - - updateKdfFields(); } void DatabaseSettingsWidgetEncryption::updateKdfFields() { - QUuid id = m_db->kdf()->uuid(); + bool isArgon2 = IS_ARGON2(m_ui->kdfComboBox->currentData().toUuid()); + m_ui->memoryUsageLabel->setVisible(isArgon2); + m_ui->memorySpinBox->setVisible(isArgon2); + m_ui->parallelismLabel->setVisible(isArgon2); + m_ui->parallelismSpinBox->setVisible(isArgon2); - m_ui->memoryUsageLabel->setVisible(IS_ARGON2(id)); - m_ui->memorySpinBox->setVisible(IS_ARGON2(id)); - m_ui->parallelismLabel->setVisible(IS_ARGON2(id)); - m_ui->parallelismSpinBox->setVisible(IS_ARGON2(id)); + loadKdfParameters(); } void DatabaseSettingsWidgetEncryption::markDirty() @@ -232,7 +251,7 @@ void DatabaseSettingsWidgetEncryption::markDirty() m_isDirty = true; } -bool DatabaseSettingsWidgetEncryption::save() +bool DatabaseSettingsWidgetEncryption::saveSettings() { Q_ASSERT(m_db); if (!m_db) { @@ -245,23 +264,21 @@ bool DatabaseSettingsWidgetEncryption::save() } if (m_db->key() && !m_db->key()->keys().isEmpty() && !m_isDirty) { - // nothing has changed, don't re-transform + // Nothing has changed, don't re-transform return true; } - auto kdf = m_db->kdf(); - Q_ASSERT(kdf); - if (!isAdvancedMode()) { + // Basic mode maintains current database KDF + auto kdf = m_db->kdf(); + Q_ASSERT(kdf); if (kdf && !m_isDirty && !m_ui->decryptionTimeSettings->isVisible()) { return true; } - int time = m_ui->decryptionTimeSlider->value() * 100; - updateFormatCompatibility(m_ui->compatibilitySelection->currentIndex(), false); - QApplication::setOverrideCursor(Qt::BusyCursor); + int time = m_ui->decryptionTimeSlider->value() * 100; int rounds = AsyncTask::runAndWaitForFuture([&kdf, time]() { return kdf->benchmark(time); }); kdf->setRounds(rounds); @@ -276,12 +293,11 @@ bool DatabaseSettingsWidgetEncryption::save() return ok; } - // remove a stored decryption time from custom data when advanced settings are used - // we don't know it until we actually run the KDF - m_db->metadata()->customData()->remove(CD_DECRYPTION_TIME_PREFERENCE_KEY); + // Advanced mode sets KDF + auto kdfChoice = m_ui->kdfComboBox->currentData().toUuid(); // first perform safety check for KDF rounds - if (IS_ARGON2(kdf->uuid()) && m_ui->transformRoundsSpinBox->value() > 10000) { + if (IS_ARGON2(kdfChoice) && m_ui->transformRoundsSpinBox->value() > 10000) { QMessageBox warning; warning.setIcon(QMessageBox::Warning); warning.setWindowTitle(tr("Number of rounds too high", "Key transformation rounds")); @@ -295,7 +311,7 @@ bool DatabaseSettingsWidgetEncryption::save() if (warning.clickedButton() != ok) { return false; } - } else if (IS_AES_KDF(kdf->uuid()) && m_ui->transformRoundsSpinBox->value() < 100000) { + } else if (IS_AES_KDF(kdfChoice) && m_ui->transformRoundsSpinBox->value() < 100000) { QMessageBox warning; warning.setIcon(QMessageBox::Warning); warning.setWindowTitle(tr("Number of rounds too low", "Key transformation rounds")); @@ -311,13 +327,18 @@ bool DatabaseSettingsWidgetEncryption::save() } } - m_db->setCipher(QUuid(m_ui->algorithmComboBox->currentData().toByteArray())); + m_db->setCipher(m_ui->algorithmComboBox->currentData().toUuid()); + + // remove a stored decryption time from custom data when advanced settings are used + // we don't know it until we actually run the KDF + m_db->metadata()->customData()->remove(CD_DECRYPTION_TIME_PREFERENCE_KEY); // Save kdf parameters + auto kdf = KeePass2::uuidToKdf(kdfChoice); kdf->setRounds(m_ui->transformRoundsSpinBox->value()); if (IS_ARGON2(kdf->uuid())) { auto argon2Kdf = kdf.staticCast(); - argon2Kdf->setMemory(static_cast(m_ui->memorySpinBox->value()) * (1 << 10)); + argon2Kdf->setMemory(Argon2Kdf::toKibibytes(m_ui->memorySpinBox->value())); argon2Kdf->setParallelism(static_cast(m_ui->parallelismSpinBox->value())); } @@ -341,17 +362,18 @@ void DatabaseSettingsWidgetEncryption::benchmarkTransformRounds(int millisecs) { QApplication::setOverrideCursor(Qt::BusyCursor); m_ui->transformBenchmarkButton->setEnabled(false); - m_ui->transformRoundsSpinBox->setFocus(); + m_ui->transformRoundsSpinBox->setEnabled(false); + m_ui->transformRoundsSpinBox->clear(); // Create a new kdf with the current parameters - auto kdf = KeePass2::uuidToKdf(QUuid(m_ui->kdfComboBox->currentData().toByteArray())); + auto kdf = KeePass2::uuidToKdf(m_ui->kdfComboBox->currentData().toUuid()); kdf->setRounds(m_ui->transformRoundsSpinBox->value()); if (IS_ARGON2(kdf->uuid())) { auto argon2Kdf = kdf.staticCast(); // Set a small static number of rounds for the benchmark argon2Kdf->setRounds(4); - if (!argon2Kdf->setMemory(static_cast(m_ui->memorySpinBox->value()) * (1 << 10))) { - m_ui->memorySpinBox->setValue(static_cast(argon2Kdf->memory() / (1 << 10))); + if (!argon2Kdf->setMemory(Argon2Kdf::toKibibytes(m_ui->memorySpinBox->value()))) { + m_ui->memorySpinBox->setValue(Argon2Kdf::toMebibytes(argon2Kdf->memory())); } if (!argon2Kdf->setParallelism(static_cast(m_ui->parallelismSpinBox->value()))) { m_ui->parallelismSpinBox->setValue(argon2Kdf->parallelism()); @@ -363,23 +385,12 @@ void DatabaseSettingsWidgetEncryption::benchmarkTransformRounds(int millisecs) m_ui->transformRoundsSpinBox->setValue(rounds); m_ui->transformBenchmarkButton->setEnabled(true); + m_ui->transformRoundsSpinBox->setEnabled(true); + m_ui->transformRoundsSpinBox->setFocus(); m_ui->decryptionTimeSlider->setValue(millisecs / 100); QApplication::restoreOverrideCursor(); } -void DatabaseSettingsWidgetEncryption::changeKdf(int index) -{ - Q_ASSERT(m_db); - if (!m_db) { - return; - } - - QUuid id(m_ui->kdfComboBox->itemData(index).toByteArray()); - m_db->setKdf(KeePass2::uuidToKdf(id)); - updateKdfFields(); - benchmarkTransformRounds(); -} - /** * Update memory spin box suffix on value change. */ @@ -405,31 +416,3 @@ void DatabaseSettingsWidgetEncryption::updateDecryptionTime(int value) { m_ui->decryptionTimeValueLabel->setText(getTextualEncryptionTime(value * 100)); } - -void DatabaseSettingsWidgetEncryption::updateFormatCompatibility(int index, bool retransform) -{ - Q_ASSERT(m_db); - if (!m_db) { - return; - } - - if (m_ui->compatibilitySelection->currentIndex() != index) { - bool block = m_ui->compatibilitySelection->blockSignals(true); - m_ui->compatibilitySelection->setCurrentIndex(index); - m_ui->compatibilitySelection->blockSignals(block); - } - - QUuid kdfUuid(m_ui->compatibilitySelection->itemData(index).toByteArray()); - if (retransform) { - auto kdf = KeePass2::uuidToKdf(kdfUuid); - m_db->setKdf(kdf); - - if (IS_ARGON2(kdf->uuid())) { - auto argon2Kdf = kdf.staticCast(); - // Default to 64 MiB of memory and 2 threads - // these settings are safe for desktop and mobile devices - argon2Kdf->setMemory(1 << 16); - argon2Kdf->setParallelism(2); - } - } -} diff --git a/src/gui/dbsettings/DatabaseSettingsWidgetEncryption.h b/src/gui/dbsettings/DatabaseSettingsWidgetEncryption.h index 874868d07..6b87bd462 100644 --- a/src/gui/dbsettings/DatabaseSettingsWidgetEncryption.h +++ b/src/gui/dbsettings/DatabaseSettingsWidgetEncryption.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2018 KeePassXC Team + * Copyright (C) 2023 KeePassXC Team * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -40,20 +40,17 @@ public: public slots: void initialize() override; void uninitialize() override; - bool save() override; + bool saveSettings() override; protected: void showEvent(QShowEvent* event) override; private slots: void benchmarkTransformRounds(int millisecs = Kdf::DEFAULT_ENCRYPTION_TIME); - void changeKdf(int index); void memoryChanged(int value); void parallelismChanged(int value); void updateDecryptionTime(int value); - void updateFormatCompatibility(int index, bool retransform = true); - void setupAlgorithmComboBox(); - void setupKdfComboBox(bool enableKdbx3); + void loadKdfAlgorithms(); void loadKdfParameters(); void updateKdfFields(); void markDirty(); @@ -71,7 +68,6 @@ private: bool m_isDirty = false; bool m_initWithAdvanced = false; - bool m_formatCompatibilityDirty = false; const QScopedPointer m_ui; }; diff --git a/src/gui/dbsettings/DatabaseSettingsWidgetEncryption.ui b/src/gui/dbsettings/DatabaseSettingsWidgetEncryption.ui index 581bc6ca2..dd5efe671 100644 --- a/src/gui/dbsettings/DatabaseSettingsWidgetEncryption.ui +++ b/src/gui/dbsettings/DatabaseSettingsWidgetEncryption.ui @@ -537,6 +537,7 @@ transformBenchmarkButton memorySpinBox parallelismSpinBox + advancedSettingsButton diff --git a/src/gui/dbsettings/DatabaseSettingsWidgetGeneral.cpp b/src/gui/dbsettings/DatabaseSettingsWidgetGeneral.cpp index d43e6d8c5..c8a9ec8dc 100644 --- a/src/gui/dbsettings/DatabaseSettingsWidgetGeneral.cpp +++ b/src/gui/dbsettings/DatabaseSettingsWidgetGeneral.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2018 KeePassXC Team + * Copyright (C) 2023 KeePassXC Team * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -18,9 +18,16 @@ #include "DatabaseSettingsWidgetGeneral.h" #include "ui_DatabaseSettingsWidgetGeneral.h" +#include +#include +#include +#include + #include "core/Clock.h" #include "core/Group.h" #include "core/Metadata.h" +#include "gui/DatabaseIcons.h" +#include "gui/IconModels.h" #include "gui/MessageBox.h" DatabaseSettingsWidgetGeneral::DatabaseSettingsWidgetGeneral(QWidget* parent) @@ -29,14 +36,17 @@ DatabaseSettingsWidgetGeneral::DatabaseSettingsWidgetGeneral(QWidget* parent) { m_ui->setupUi(this); + connect(m_ui->dbPublicColorButton, &QPushButton::clicked, this, &DatabaseSettingsWidgetGeneral::pickPublicColor); + connect(m_ui->dbPublicColorClearButton, &QPushButton::clicked, this, [this] { setupPublicColorButton({}); }); + connect(m_ui->dbPublicIconButton, &QPushButton::clicked, this, &DatabaseSettingsWidgetGeneral::pickPublicIcon); + connect(m_ui->dbPublicIconClearButton, &QPushButton::clicked, this, [this] { setupPublicIconButton(-1); }); + connect(m_ui->historyMaxItemsCheckBox, SIGNAL(toggled(bool)), m_ui->historyMaxItemsSpinBox, SLOT(setEnabled(bool))); connect(m_ui->historyMaxSizeCheckBox, SIGNAL(toggled(bool)), m_ui->historyMaxSizeSpinBox, SLOT(setEnabled(bool))); connect(m_ui->autosaveDelayCheckBox, SIGNAL(toggled(bool)), m_ui->autosaveDelaySpinBox, SLOT(setEnabled(bool))); } -DatabaseSettingsWidgetGeneral::~DatabaseSettingsWidgetGeneral() -{ -} +DatabaseSettingsWidgetGeneral::~DatabaseSettingsWidgetGeneral() = default; void DatabaseSettingsWidgetGeneral::initialize() { @@ -48,6 +58,10 @@ void DatabaseSettingsWidgetGeneral::initialize() m_ui->defaultUsernameEdit->setText(meta->defaultUserName()); m_ui->compressionCheckbox->setChecked(m_db->compressionAlgorithm() != Database::CompressionNone); + m_ui->dbPublicName->setText(m_db->publicName()); + setupPublicColorButton(m_db->publicColor()); + setupPublicIconButton(m_db->publicIcon()); + if (meta->historyMaxItems() > -1) { m_ui->historyMaxItemsSpinBox->setValue(meta->historyMaxItems()); m_ui->historyMaxItemsCheckBox->setChecked(true); @@ -84,7 +98,7 @@ void DatabaseSettingsWidgetGeneral::showEvent(QShowEvent* event) m_ui->dbNameEdit->setFocus(); } -bool DatabaseSettingsWidgetGeneral::save() +bool DatabaseSettingsWidgetGeneral::saveSettings() { auto* meta = m_db->metadata(); @@ -118,6 +132,10 @@ bool DatabaseSettingsWidgetGeneral::save() meta->setRecycleBinEnabled(m_ui->recycleBinEnabledCheckBox->isChecked()); meta->setSettingsChanged(Clock::currentDateTimeUtc()); + m_db->setPublicName(m_ui->dbPublicName->text()); + m_db->setPublicColor(m_ui->dbPublicColorButton->property("color").toString()); + m_db->setPublicIcon(m_ui->dbPublicIconButton->property("iconIndex").toInt()); + bool truncate = false; int historyMaxItems; @@ -157,3 +175,79 @@ bool DatabaseSettingsWidgetGeneral::save() return true; } + +void DatabaseSettingsWidgetGeneral::pickPublicColor() +{ + auto oldColor = QColor(m_ui->dbPublicColorButton->property("color").toString()); + auto newColor = QColorDialog::getColor(oldColor); + if (newColor.isValid()) { + setupPublicColorButton(newColor); + } +} + +void DatabaseSettingsWidgetGeneral::setupPublicColorButton(const QColor& color) +{ + m_ui->dbPublicColorClearButton->setVisible(color.isValid()); + if (color.isValid()) { + m_ui->dbPublicColorButton->setStyleSheet(QString("background-color:%1").arg(color.name())); + m_ui->dbPublicColorButton->setProperty("color", color.name()); + } else { + m_ui->dbPublicColorButton->setStyleSheet(""); + m_ui->dbPublicColorButton->setProperty("color", {}); + } +} + +void DatabaseSettingsWidgetGeneral::pickPublicIcon() +{ + QDialog dialog(this); + dialog.setSizeGripEnabled(false); + dialog.setWindowTitle(tr("Select Database Icon")); + + auto iconList = new QListView; + iconList->setFlow(QListView::LeftToRight); + iconList->setMovement(QListView::Static); + iconList->setResizeMode(QListView::Adjust); + iconList->setWrapping(true); + iconList->setSpacing(4); + + auto iconModel = new DefaultIconModel; + iconList->setModel(iconModel); + if (m_ui->dbPublicIconButton->property("iconIndex").toInt() >= 0) { + iconList->setCurrentIndex(iconModel->index(m_ui->dbPublicIconButton->property("iconIndex").toInt(), 0)); + } else { + iconList->setCurrentIndex(iconModel->index(0, 0)); + } + + auto buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel); + auto layout = new QVBoxLayout(&dialog); + layout->addWidget(iconList); + layout->addWidget(buttonBox); + + // Resize the dialog to fit the default icon list + auto cellSize = iconList->sizeHintForIndex(iconModel->index(0, 0)); + auto spacing = iconList->spacing() * 2; + dialog.resize((cellSize.width() + spacing) * 15, (cellSize.height() + spacing) * 6 + 16); + + connect(iconList, &QListView::doubleClicked, &dialog, &QDialog::accept); + connect(buttonBox, &QDialogButtonBox::accepted, &dialog, &QDialog::accept); + connect(buttonBox, &QDialogButtonBox::rejected, &dialog, &QDialog::reject); + connect( + &dialog, &QDialog::accepted, this, [this, iconList] { setupPublicIconButton(iconList->currentIndex().row()); }); + + dialog.exec(); +} + +void DatabaseSettingsWidgetGeneral::setupPublicIconButton(int iconIndex) +{ + auto valid = iconIndex >= 0 && iconIndex < databaseIcons()->count(); + m_ui->dbPublicIconClearButton->setVisible(valid); + if (valid) { + m_ui->dbPublicIconButton->setIcon(databaseIcons()->icon(iconIndex)); + m_ui->dbPublicIconButton->setProperty("iconIndex", iconIndex); + m_ui->dbPublicIconClearButton->setVisible(true); + } else { + m_ui->dbPublicIconButton->setIcon(QIcon()); + m_ui->dbPublicIconButton->setProperty("iconIndex", -1); + m_ui->dbPublicIconClearButton->setVisible(false); + } +} diff --git a/src/gui/dbsettings/DatabaseSettingsWidgetGeneral.h b/src/gui/dbsettings/DatabaseSettingsWidgetGeneral.h index a26e1ef7a..7c0c1ebe9 100644 --- a/src/gui/dbsettings/DatabaseSettingsWidgetGeneral.h +++ b/src/gui/dbsettings/DatabaseSettingsWidgetGeneral.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2018 KeePassXC Team + * Copyright (C) 2023 KeePassXC Team * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -20,6 +20,8 @@ #include "DatabaseSettingsWidget.h" +#include + class Database; namespace Ui { @@ -38,11 +40,18 @@ public: public slots: void initialize() override; void uninitialize() override; - bool save() override; + bool saveSettings() override; protected: void showEvent(QShowEvent* event) override; +private slots: + void pickPublicColor(); + void setupPublicColorButton(const QColor& color); + void pickPublicIcon(); + void setupPublicIconButton(int iconIndex); + +private: const QScopedPointer m_ui; }; diff --git a/src/gui/dbsettings/DatabaseSettingsWidgetGeneral.ui b/src/gui/dbsettings/DatabaseSettingsWidgetGeneral.ui index 939b69963..324ae6d3d 100644 --- a/src/gui/dbsettings/DatabaseSettingsWidgetGeneral.ui +++ b/src/gui/dbsettings/DatabaseSettingsWidgetGeneral.ui @@ -7,7 +7,7 @@ 0 0 453 - 394 + 647 @@ -92,6 +92,151 @@ + + + + Public Database Metadata + + + + + + + true + + + + Warning: the following settings are not encrypted. + + + + + + + 0 + + + + + Display name: + + + + + + + Publically visible display name used on the unlock dialog + + + Database public display name + + + + + + + Display color: + + + + + + + + + + 30 + 30 + + + + Publically visible color used on the unlock dialog + + + Database public display color chooser + + + + + + + + + + Clear + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + Display icon: + + + + + + + + + + 30 + 30 + + + + + + + + 30 + 30 + + + + + + + + Clear + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + @@ -113,6 +258,19 @@ of entries remain at most. + + + + Move entries to a recycle bin group +instead of deleting them from the database. +Entries deleted from the recycle bin are +removed from the database. + + + Use recycle bin + + + @@ -158,19 +316,6 @@ add up to the specified amount at most. - - - - Move entries to a recycle bin group -instead of deleting them from the database. -Entries deleted from the recycle bin are -removed from the database. - - - Use recycle bin - - - diff --git a/src/gui/dbsettings/DatabaseSettingsWidgetMaintenance.cpp b/src/gui/dbsettings/DatabaseSettingsWidgetMaintenance.cpp index 09650c6b0..fea6bc2a3 100644 --- a/src/gui/dbsettings/DatabaseSettingsWidgetMaintenance.cpp +++ b/src/gui/dbsettings/DatabaseSettingsWidgetMaintenance.cpp @@ -42,9 +42,7 @@ DatabaseSettingsWidgetMaintenance::DatabaseSettingsWidgetMaintenance(QWidget* pa SLOT(selectionChanged())); } -DatabaseSettingsWidgetMaintenance::~DatabaseSettingsWidgetMaintenance() -{ -} +DatabaseSettingsWidgetMaintenance::~DatabaseSettingsWidgetMaintenance() = default; void DatabaseSettingsWidgetMaintenance::populateIcons(QSharedPointer db) { diff --git a/src/gui/dbsettings/DatabaseSettingsWidgetMaintenance.h b/src/gui/dbsettings/DatabaseSettingsWidgetMaintenance.h index e17689f9e..463ad89a8 100644 --- a/src/gui/dbsettings/DatabaseSettingsWidgetMaintenance.h +++ b/src/gui/dbsettings/DatabaseSettingsWidgetMaintenance.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2021 KeePassXC Team + * Copyright (C) 2023 KeePassXC Team * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -39,8 +39,8 @@ public: public slots: void initialize() override; - void uninitialize() override{}; - inline bool save() override + void uninitialize() override {}; + inline bool saveSettings() override { return true; }; diff --git a/src/gui/dbsettings/DatabaseSettingsWidgetMetaDataSimple.cpp b/src/gui/dbsettings/DatabaseSettingsWidgetMetaDataSimple.cpp index 0a1dccb5f..f474fe8d6 100644 --- a/src/gui/dbsettings/DatabaseSettingsWidgetMetaDataSimple.cpp +++ b/src/gui/dbsettings/DatabaseSettingsWidgetMetaDataSimple.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2018 KeePassXC Team + * Copyright (C) 2023 KeePassXC Team * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -28,9 +28,7 @@ DatabaseSettingWidgetMetaData::DatabaseSettingWidgetMetaData(QWidget* parent) m_ui->setupUi(this); } -DatabaseSettingWidgetMetaData::~DatabaseSettingWidgetMetaData() -{ -} +DatabaseSettingWidgetMetaData::~DatabaseSettingWidgetMetaData() = default; void DatabaseSettingWidgetMetaData::initialize() { @@ -53,7 +51,7 @@ void DatabaseSettingWidgetMetaData::uninitialize() { } -bool DatabaseSettingWidgetMetaData::save() +bool DatabaseSettingWidgetMetaData::saveSettings() { Metadata* meta = m_db->metadata(); meta->setName(m_ui->databaseName->text()); diff --git a/src/gui/dbsettings/DatabaseSettingsWidgetMetaDataSimple.h b/src/gui/dbsettings/DatabaseSettingsWidgetMetaDataSimple.h index 8a32e0670..2aee80813 100644 --- a/src/gui/dbsettings/DatabaseSettingsWidgetMetaDataSimple.h +++ b/src/gui/dbsettings/DatabaseSettingsWidgetMetaDataSimple.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2018 KeePassXC Team + * Copyright (C) 2023 KeePassXC Team * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -38,7 +38,7 @@ public: public slots: void initialize() override; void uninitialize() override; - bool save() override; + bool saveSettings() override; protected: void showEvent(QShowEvent* event) override; diff --git a/src/gui/entry/AutoTypeAssociationsModel.cpp b/src/gui/entry/AutoTypeAssociationsModel.cpp index 6e7b08bc0..03eedae25 100644 --- a/src/gui/entry/AutoTypeAssociationsModel.cpp +++ b/src/gui/entry/AutoTypeAssociationsModel.cpp @@ -79,14 +79,14 @@ QVariant AutoTypeAssociationsModel::headerData(int section, Qt::Orientation orie return tr("Sequence"); } } else { - return QVariant(); + return {}; } } QVariant AutoTypeAssociationsModel::data(const QModelIndex& index, int role) const { if (!index.isValid()) { - return QVariant(); + return {}; } if (role == Qt::DisplayRole) { @@ -108,7 +108,7 @@ QVariant AutoTypeAssociationsModel::data(const QModelIndex& index, int role) con return sequence; } } else { - return QVariant(); + return {}; } } diff --git a/src/gui/entry/EditEntryAttachmentsDialog.cpp b/src/gui/entry/EditEntryAttachmentsDialog.cpp new file mode 100644 index 000000000..047f0a6b4 --- /dev/null +++ b/src/gui/entry/EditEntryAttachmentsDialog.cpp @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2025 KeePassXC Team + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 or (at your option) + * version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "EditEntryAttachmentsDialog.h" +#include "ui_EditEntryAttachmentsDialog.h" + +#include + +#include +#include +#include +#include + +EditEntryAttachmentsDialog::EditEntryAttachmentsDialog(QWidget* parent) + : QDialog(parent) + , m_ui(new Ui::EditEntryAttachmentsDialog) +{ + m_ui->setupUi(this); + + m_ui->dialogButtons->setStandardButtons(QDialogButtonBox::Ok | QDialogButtonBox::Cancel); + + connect(m_ui->dialogButtons, &QDialogButtonBox::accepted, this, &EditEntryAttachmentsDialog::accept); + connect(m_ui->dialogButtons, &QDialogButtonBox::rejected, this, &EditEntryAttachmentsDialog::reject); +} + +EditEntryAttachmentsDialog::~EditEntryAttachmentsDialog() = default; + +void EditEntryAttachmentsDialog::setAttachment(attachments::Attachment attachment) +{ + setWindowTitle(tr("Edit: %1").arg(attachment.name)); + + m_ui->attachmentWidget->openAttachment(std::move(attachment), attachments::OpenMode::ReadWrite); +} + +attachments::Attachment EditEntryAttachmentsDialog::getAttachment() const +{ + return m_ui->attachmentWidget->getAttachment(); +} diff --git a/src/gui/entry/EditEntryAttachmentsDialog.h b/src/gui/entry/EditEntryAttachmentsDialog.h new file mode 100644 index 000000000..38c77179a --- /dev/null +++ b/src/gui/entry/EditEntryAttachmentsDialog.h @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2025 KeePassXC Team + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 or (at your option) + * version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once + +#include "attachments/AttachmentTypes.h" + +#include +#include + +namespace Ui +{ + class EditEntryAttachmentsDialog; +} + +class EntryAttachments; + +class EditEntryAttachmentsDialog : public QDialog +{ + Q_OBJECT + +public: + explicit EditEntryAttachmentsDialog(QWidget* parent = nullptr); + ~EditEntryAttachmentsDialog() override; + + void setAttachment(attachments::Attachment attachment); + attachments::Attachment getAttachment() const; + +private: + QScopedPointer m_ui; +}; diff --git a/src/gui/entry/EditEntryAttachmentsDialog.ui b/src/gui/entry/EditEntryAttachmentsDialog.ui new file mode 100644 index 000000000..b958f966d --- /dev/null +++ b/src/gui/entry/EditEntryAttachmentsDialog.ui @@ -0,0 +1,46 @@ + + + EditEntryAttachmentsDialog + + + + 0 + 0 + 447 + 424 + + + + + + + + + + + 0 + 0 + + + + + + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + + AttachmentWidget + QWidget +
    gui/entry/attachments/AttachmentWidget.h
    + 1 +
    +
    + + +
    diff --git a/src/gui/entry/EditEntryWidget.cpp b/src/gui/entry/EditEntryWidget.cpp index 2b6960753..d2213a669 100644 --- a/src/gui/entry/EditEntryWidget.cpp +++ b/src/gui/entry/EditEntryWidget.cpp @@ -41,6 +41,7 @@ #include "core/TimeDelta.h" #ifdef WITH_XC_SSHAGENT #include "sshagent/OpenSSHKey.h" +#include "sshagent/OpenSSHKeyGenDialog.h" #include "sshagent/SSHAgent.h" #endif #ifdef WITH_XC_BROWSER @@ -136,8 +137,47 @@ EditEntryWidget::EditEntryWidget(QWidget* parent) m_mainUi->passwordEdit->setQualityVisible(true); } -EditEntryWidget::~EditEntryWidget() +EditEntryWidget::~EditEntryWidget() = default; + +bool EditEntryWidget::switchToPage(Page page) { + auto index = pageIndex(widgetForPage(page)); + if (index >= 0) { + setCurrentPage(index); + return true; + } + return false; +} + +QWidget* EditEntryWidget::widgetForPage(Page page) const +{ + switch (page) { + case Page::Main: + return m_mainWidget; + case Page::Advanced: + return m_advancedWidget; + case Page::Icon: + return m_iconsWidget; + case Page::AutoType: + return m_autoTypeWidget; + case Page::Browser: +#ifdef WITH_XC_BROWSER + return m_browserWidget; +#else + return nullptr; +#endif + case Page::SSHAgent: +#ifdef WITH_XC_SSHAGENT + return m_sshAgentWidget; +#else + return nullptr; +#endif + case Page::Properties: + return m_editWidgetProperties; + case Page::History: + return m_historyWidget; + } + return nullptr; } void EditEntryWidget::setupMain() @@ -547,6 +587,7 @@ void EditEntryWidget::updateHistoryButtons(const QModelIndex& current, const QMo #ifdef WITH_XC_SSHAGENT void EditEntryWidget::setupSSHAgent() { + m_pendingPrivateKey = ""; m_sshAgentUi->setupUi(m_sshAgentWidget); QFont fixedFont = Font::fixedFont(); @@ -565,8 +606,10 @@ void EditEntryWidget::setupSSHAgent() connect(m_sshAgentUi->browseButton, &QPushButton::clicked, this, &EditEntryWidget::browsePrivateKey); connect(m_sshAgentUi->addToAgentButton, &QPushButton::clicked, this, &EditEntryWidget::addKeyToAgent); connect(m_sshAgentUi->removeFromAgentButton, &QPushButton::clicked, this, &EditEntryWidget::removeKeyFromAgent); + connect(m_sshAgentUi->clearAgentButton, &QPushButton::clicked, this, &EditEntryWidget::clearAgent); connect(m_sshAgentUi->decryptButton, &QPushButton::clicked, this, &EditEntryWidget::decryptPrivateKey); connect(m_sshAgentUi->copyToClipboardButton, &QPushButton::clicked, this, &EditEntryWidget::copyPublicKey); + connect(m_sshAgentUi->generateButton, &QPushButton::clicked, this, &EditEntryWidget::generatePrivateKey); connect(m_attachments.data(), &EntryAttachments::modified, this, &EditEntryWidget::updateSSHAgentAttachments); @@ -594,6 +637,12 @@ void EditEntryWidget::updateSSHAgent() m_sshAgentSettings.fromEntry(m_entry); setSSHAgentSettings(); + if (!m_pendingPrivateKey.isEmpty()) { + m_sshAgentSettings.setAttachmentName(m_pendingPrivateKey); + m_sshAgentSettings.setSelectedType("attachment"); + m_pendingPrivateKey = ""; + } + updateSSHAgentAttachments(); } @@ -654,29 +703,24 @@ void EditEntryWidget::updateSSHAgentKeyInfo() if (!key.fingerprint().isEmpty()) { m_sshAgentUi->fingerprintTextLabel->setText(key.fingerprint(QCryptographicHash::Md5) + "\n" + key.fingerprint(QCryptographicHash::Sha256)); - } else { - m_sshAgentUi->fingerprintTextLabel->setText(tr("(encrypted)")); } - if (!key.comment().isEmpty() || !key.encrypted()) { + if (!key.comment().isEmpty()) { m_sshAgentUi->commentTextLabel->setText(key.comment()); - } else { - m_sshAgentUi->commentTextLabel->setText(tr("(encrypted)")); - m_sshAgentUi->decryptButton->setEnabled(true); } + m_sshAgentUi->decryptButton->setEnabled(key.encrypted()); + if (!key.publicKey().isEmpty()) { m_sshAgentUi->publicKeyEdit->document()->setPlainText(key.publicKey()); m_sshAgentUi->copyToClipboardButton->setEnabled(true); - } else { - m_sshAgentUi->publicKeyEdit->document()->setPlainText(tr("(encrypted)")); - m_sshAgentUi->copyToClipboardButton->setDisabled(true); } // enable agent buttons only if we have an agent running if (sshAgent()->isAgentRunning()) { m_sshAgentUi->addToAgentButton->setEnabled(true); m_sshAgentUi->removeFromAgentButton->setEnabled(true); + m_sshAgentUi->clearAgentButton->setEnabled(true); sshAgent()->setAutoRemoveOnLock(key, m_sshAgentUi->removeKeyFromAgentCheckBox->isChecked()); } @@ -779,11 +823,18 @@ void EditEntryWidget::removeKeyFromAgent() } } +void EditEntryWidget::clearAgent() +{ + auto ret = sshAgent()->clearAllAgentIdentities(); + showMessage(sshAgent()->errorString(), ret ? MessageWidget::Positive : KMessageWidget::Error); +} + void EditEntryWidget::decryptPrivateKey() { OpenSSHKey key; if (!getOpenSSHKey(key, true)) { + showMessage(tr("Failed to decrypt SSH key, ensure password is correct."), MessageWidget::Error); return; } @@ -797,18 +848,51 @@ void EditEntryWidget::decryptPrivateKey() + key.fingerprint(QCryptographicHash::Sha256)); m_sshAgentUi->publicKeyEdit->document()->setPlainText(key.publicKey()); m_sshAgentUi->copyToClipboardButton->setEnabled(true); + m_sshAgentUi->decryptButton->setEnabled(false); } void EditEntryWidget::copyPublicKey() { clipboard()->setText(m_sshAgentUi->publicKeyEdit->document()->toPlainText()); } + +void EditEntryWidget::generatePrivateKey() +{ + auto dialog = new OpenSSHKeyGenDialog(this); + + OpenSSHKey key; + dialog->setKey(&key); + + if (dialog->exec()) { + // derive openssh naming from type + QString keyPrefix = key.type(); + if (keyPrefix.startsWith("ecdsa")) { + keyPrefix = "id_ecdsa"; + } else { + keyPrefix.replace("ssh-", "id_"); + } + + for (int i = 0; i < 10; i++) { + QString keyName = keyPrefix; + + if (i > 0) { + keyName += "." + QString::number(i); + } + + if (!m_entry->attachments()->hasKey(keyName)) { + m_pendingPrivateKey = keyName; + m_entry->attachments()->set(m_pendingPrivateKey, key.privateKey().toUtf8()); + break; + } + } + } +} #endif void EditEntryWidget::useExpiryPreset(QAction* action) { m_mainUi->expireCheck->setChecked(true); - TimeDelta delta = action->data().value(); + auto delta = action->data().value(); QDateTime now = Clock::currentDateTime(); QDateTime expiryDateTime = now + delta; m_mainUi->expireDatePicker->setDateTime(expiryDateTime); @@ -851,7 +935,7 @@ void EditEntryWidget::loadEntry(Entry* entry, setForms(entry); setReadOnly(m_history); - setCurrentPage(0); + switchToPage(Page::Main); setPageHidden(m_historyWidget, m_history || m_entry->historyItems().count() < 1); #ifdef WITH_XC_SSHAGENT setPageHidden(m_sshAgentWidget, !sshAgent()->isEnabled()); @@ -878,6 +962,7 @@ void EditEntryWidget::setForms(Entry* entry, bool restore) m_mainUi->expireDatePicker->setReadOnly(m_history); m_mainUi->revealNotesButton->setIcon(icons()->onOffIcon("password-show", false)); m_mainUi->revealNotesButton->setVisible(config()->get(Config::Security_HideNotes).toBool()); + m_mainUi->revealNotesButton->setChecked(false); m_mainUi->notesEdit->setReadOnly(m_history); m_mainUi->notesEdit->setVisible(!config()->get(Config::Security_HideNotes).toBool()); if (config()->get(Config::GUI_MonospaceNotes).toBool()) { @@ -1095,7 +1180,7 @@ bool EditEntryWidget::commitEntry() MessageBox::Yes | MessageBox::No, MessageBox::Yes); if (res == MessageBox::Yes) { - setCurrentPage(3); + switchToPage(Page::AutoType); return false; } } @@ -1110,7 +1195,7 @@ bool EditEntryWidget::commitEntry() MessageBox::Yes | MessageBox::No, MessageBox::Yes); if (res == MessageBox::Yes) { - setCurrentPage(3); + switchToPage(Page::AutoType); return false; } } @@ -1185,7 +1270,10 @@ void EditEntryWidget::updateEntryData(Entry* entry) const entry->setPassword(m_mainUi->passwordEdit->text()); entry->setExpires(m_mainUi->expireCheck->isChecked()); entry->setExpiryTime(m_mainUi->expireDatePicker->dateTime().toUTC()); - entry->setTags(m_mainUi->tagsList->tags().toSet().toList().join(";")); // remove repeated tags + + QStringList uniqueTags(m_mainUi->tagsList->tags()); + uniqueTags.removeDuplicates(); + entry->setTags(uniqueTags.join(";")); entry->setNotes(m_mainUi->notesEdit->toPlainText()); diff --git a/src/gui/entry/EditEntryWidget.h b/src/gui/entry/EditEntryWidget.h index fddf64eda..3fce4d56d 100644 --- a/src/gui/entry/EditEntryWidget.h +++ b/src/gui/entry/EditEntryWidget.h @@ -77,6 +77,19 @@ public: Entry* currentEntry() const; void clear(); + enum class Page + { + Main, + Advanced, + Icon, + AutoType, + Browser, + SSHAgent, + Properties, + History + }; + bool switchToPage(Page page); + signals: void editFinished(bool accepted); void historyEntryActivated(Entry* entry); @@ -122,8 +135,10 @@ private slots: void browsePrivateKey(); void addKeyToAgent(); void removeKeyFromAgent(); + void clearAgent(); void decryptPrivateKey(); void copyPublicKey(); + void generatePrivateKey(); #endif #ifdef WITH_XC_BROWSER void updateBrowserModified(); @@ -151,7 +166,6 @@ private: void setupEntryUpdate(); void setupColorButton(bool foreground, const QColor& color); - bool passwordsEqual(); void setForms(Entry* entry, bool restore = false); QMenu* createPresetsMenu(); void updateEntryData(Entry* entry) const; @@ -162,6 +176,8 @@ private: void displayAttribute(QModelIndex index, bool showProtected); + QWidget* widgetForPage(Page page) const; + QPointer m_entry; QSharedPointer m_db; @@ -169,6 +185,7 @@ private: bool m_history; #ifdef WITH_XC_SSHAGENT KeeAgentSettings m_sshAgentSettings; + QString m_pendingPrivateKey; #endif const QScopedPointer m_mainUi; const QScopedPointer m_advancedUi; diff --git a/src/gui/entry/EditEntryWidgetBrowser.ui b/src/gui/entry/EditEntryWidgetBrowser.ui index 8c3697597..7b4d5016b 100644 --- a/src/gui/entry/EditEntryWidgetBrowser.ui +++ b/src/gui/entry/EditEntryWidgetBrowser.ui @@ -63,7 +63,7 @@ - Only send this setting to the browser for HTTP Auth dialogs. If enabled, normal login forms will not show this entry for selection. + Only send this entry to the browser for HTTP Auth dialogs. If enabled, normal login forms will not show this entry for selection. Use this entry only with HTTP Basic Auth @@ -73,7 +73,7 @@ - Do not send this setting to the browser for HTTP Auth dialogs. If enabled, HTTP Auth dialogs will not show this entry for selection. + Do not send this entry to the browser for HTTP Auth dialogs. If enabled, HTTP Auth dialogs will not show this entry for selection. Do not use this entry with HTTP Basic Auth diff --git a/src/gui/entry/EditEntryWidgetMain.ui b/src/gui/entry/EditEntryWidgetMain.ui index 6fe6637e7..6816b090f 100644 --- a/src/gui/entry/EditEntryWidgetMain.ui +++ b/src/gui/entry/EditEntryWidgetMain.ui @@ -105,6 +105,9 @@ Notes field + + 10.000000000000000 + diff --git a/src/gui/entry/EditEntryWidgetSSHAgent.ui b/src/gui/entry/EditEntryWidgetSSHAgent.ui index 81fac082a..3215c1a27 100644 --- a/src/gui/entry/EditEntryWidgetSSHAgent.ui +++ b/src/gui/entry/EditEntryWidgetSSHAgent.ui @@ -118,23 +118,6 @@ Private key - - - - External file - - - - - - - Browser for key file - - - Browse… - - - @@ -145,7 +128,7 @@ - + Qt::ClickFocus @@ -155,8 +138,8 @@ - - + + @@ -171,9 +154,40 @@ + + + + Clear agent + + + - + + + + External file + + + + + + + Browser for key file + + + Browse… + + + + + + + Generate + + + + @@ -325,7 +339,6 @@ lifetimeCheckBox lifetimeSpinBox attachmentRadioButton - attachmentComboBox externalFileRadioButton browseButton addToAgentButton diff --git a/src/gui/entry/EntryAttachmentsModel.cpp b/src/gui/entry/EntryAttachmentsModel.cpp index c5d0ff073..96a55ed72 100644 --- a/src/gui/entry/EntryAttachmentsModel.cpp +++ b/src/gui/entry/EntryAttachmentsModel.cpp @@ -79,7 +79,7 @@ QVariant EntryAttachmentsModel::headerData(int section, Qt::Orientation orientat QVariant EntryAttachmentsModel::data(const QModelIndex& index, int role) const { if (!index.isValid()) { - return QVariant(); + return {}; } if (role == Qt::DisplayRole || role == Qt::EditRole) { @@ -96,7 +96,7 @@ QVariant EntryAttachmentsModel::data(const QModelIndex& index, int role) const } } - return QVariant(); + return {}; } bool EntryAttachmentsModel::setData(const QModelIndex& index, const QVariant& value, int role) @@ -124,12 +124,21 @@ Qt::ItemFlags EntryAttachmentsModel::flags(const QModelIndex& index) const QString EntryAttachmentsModel::keyByIndex(const QModelIndex& index) const { if (!index.isValid()) { - return QString(); + return {}; } return m_entryAttachments->keys().at(index.row()); } +int EntryAttachmentsModel::rowByKey(const QString& key) const +{ + if (!m_entryAttachments) { + return -1; + } + + return m_entryAttachments->keys().indexOf(key); +} + void EntryAttachmentsModel::attachmentChange(const QString& key) { int row = m_entryAttachments->keys().indexOf(key); diff --git a/src/gui/entry/EntryAttachmentsModel.h b/src/gui/entry/EntryAttachmentsModel.h index d155f25ca..ea541ebf7 100644 --- a/src/gui/entry/EntryAttachmentsModel.h +++ b/src/gui/entry/EntryAttachmentsModel.h @@ -44,6 +44,7 @@ public: bool setData(const QModelIndex& index, const QVariant& value, int role = Qt::EditRole) override; Qt::ItemFlags flags(const QModelIndex& index) const override; QString keyByIndex(const QModelIndex& index) const; + int rowByKey(const QString& key) const; private slots: void attachmentChange(const QString& key); diff --git a/src/gui/entry/EntryAttachmentsWidget.cpp b/src/gui/entry/EntryAttachmentsWidget.cpp index d8634f275..a3b7fc763 100644 --- a/src/gui/entry/EntryAttachmentsWidget.cpp +++ b/src/gui/entry/EntryAttachmentsWidget.cpp @@ -16,21 +16,42 @@ */ #include "EntryAttachmentsWidget.h" + +#include "EditEntryAttachmentsDialog.h" +#include "EntryAttachmentsModel.h" +#include "PreviewEntryAttachmentsDialog.h" #include "ui_EntryAttachmentsWidget.h" -#include +#include #include +#include +#include #include #include #include -#include "EntryAttachmentsModel.h" -#include "core/Config.h" #include "core/EntryAttachments.h" #include "core/Tools.h" #include "gui/FileDialog.h" #include "gui/MessageBox.h" +namespace +{ + constexpr const char* DefaultName = "New Attachment"; + constexpr const char* Suffix = ".txt"; + + QString generateUniqueName(const QString& name, const QStringList& existingNames) + { + uint64_t i = 0; + QString newName = QStringLiteral("%1%2").arg(name).arg(Suffix); + while (existingNames.contains(newName)) { + newName = QStringLiteral("%1_%2%3").arg(name).arg(++i).arg(Suffix); + } + return newName; + } + +} // namespace + EntryAttachmentsWidget::EntryAttachmentsWidget(QWidget* parent) : QWidget(parent) , m_ui(new Ui::EntryAttachmentsWidget) @@ -46,12 +67,12 @@ EntryAttachmentsWidget::EntryAttachmentsWidget(QWidget* parent) m_ui->attachmentsView->viewport()->installEventFilter(this); m_ui->attachmentsView->setModel(m_attachmentsModel); - m_ui->attachmentsView->verticalHeader()->hide(); - m_ui->attachmentsView->horizontalHeader()->setStretchLastSection(true); - m_ui->attachmentsView->horizontalHeader()->resizeSection(EntryAttachmentsModel::NameColumn, 400); - m_ui->attachmentsView->setSelectionBehavior(QAbstractItemView::SelectRows); - m_ui->attachmentsView->setSelectionMode(QAbstractItemView::ExtendedSelection); - m_ui->attachmentsView->setEditTriggers(QAbstractItemView::SelectedClicked); + m_ui->attachmentsView->horizontalHeader()->setMinimumSectionSize(70); + m_ui->attachmentsView->horizontalHeader()->setSectionResizeMode(EntryAttachmentsModel::NameColumn, + QHeaderView::Stretch); + m_ui->attachmentsView->horizontalHeader()->setSectionResizeMode(EntryAttachmentsModel::SizeColumn, + QHeaderView::ResizeToContents); + m_ui->attachmentsView->verticalHeader()->setSectionResizeMode(QHeaderView::ResizeToContents); connect(this, SIGNAL(buttonsVisibleChanged(bool)), this, SLOT(updateButtonsVisible())); connect(this, SIGNAL(readOnlyChanged(bool)), SLOT(updateButtonsEnabled())); @@ -64,20 +85,35 @@ EntryAttachmentsWidget::EntryAttachmentsWidget(QWidget* parent) // clang-format on connect(this, SIGNAL(readOnlyChanged(bool)), m_attachmentsModel, SLOT(setReadOnly(bool))); - connect(m_ui->attachmentsView, SIGNAL(doubleClicked(QModelIndex)), SLOT(openAttachment(QModelIndex))); + connect(m_ui->attachmentsView, &QAbstractItemView::doubleClicked, [this](const QModelIndex&) { + m_readOnly ? previewSelectedAttachment() : editSelectedAttachment(); + }); + + connect(m_ui->attachmentsView->itemDelegate(), &QAbstractItemDelegate::commitData, [this](QWidget* editor) { + if (auto lineEdit = qobject_cast(editor)) { + auto index = m_attachmentsModel->rowByKey(lineEdit->text()); + m_ui->attachmentsView->setCurrentIndex(m_attachmentsModel->index(index, 0)); + } + }); + connect(m_ui->saveAttachmentButton, SIGNAL(clicked()), SLOT(saveSelectedAttachments())); connect(m_ui->openAttachmentButton, SIGNAL(clicked()), SLOT(openSelectedAttachments())); connect(m_ui->addAttachmentButton, SIGNAL(clicked()), SLOT(insertAttachments())); + connect(m_ui->editAttachmentButton, SIGNAL(clicked()), SLOT(editSelectedAttachment())); + connect(m_ui->previewAttachmentButton, SIGNAL(clicked()), SLOT(previewSelectedAttachment())); connect(m_ui->removeAttachmentButton, SIGNAL(clicked()), SLOT(removeSelectedAttachments())); - connect(m_ui->renameAttachmentButton, SIGNAL(clicked()), SLOT(renameSelectedAttachments())); + + auto addButtonMenu = new QMenu(this); + addButtonMenu->addAction(tr("New Text Document"), this, &EntryAttachmentsWidget::newAttachments); + addButtonMenu->addAction(tr("Load from Disk…"), this, QOverload<>::of(&EntryAttachmentsWidget::insertAttachments)); + + m_ui->addAttachmentButton->setMenu(addButtonMenu); updateButtonsVisible(); updateButtonsEnabled(); } -EntryAttachmentsWidget::~EntryAttachmentsWidget() -{ -} +EntryAttachmentsWidget::~EntryAttachmentsWidget() = default; const EntryAttachments* EntryAttachmentsWidget::attachments() const { @@ -165,6 +201,117 @@ void EntryAttachmentsWidget::insertAttachments() emit widgetUpdated(); } +void EntryAttachmentsWidget::newAttachments() +{ + Q_ASSERT(m_entryAttachments); + Q_ASSERT(!isReadOnly()); + if (isReadOnly()) { + return; + } + + // Create a temporary file to allow the user to edit the attachment + auto newFileName = generateUniqueName(DefaultName, m_entryAttachments->keys()); + m_entryAttachments->set(newFileName, QByteArray()); + + auto currentIndex = m_attachmentsModel->index(m_attachmentsModel->rowByKey(newFileName), 0); + m_ui->attachmentsView->setCurrentIndex(currentIndex); + m_ui->attachmentsView->edit(currentIndex); +} + +void EntryAttachmentsWidget::previewSelectedAttachment() +{ + Q_ASSERT(m_entryAttachments); + + const auto selectionModel = m_ui->attachmentsView->selectionModel(); + if (!selectionModel) { + qWarning() << "Failed to preview an attachment: No selection model"; + return; + } + + auto indexes = selectionModel->selectedIndexes(); + if (indexes.empty()) { + qWarning() << "Failed to edit an attachment: No attachment selected"; + return; + } + + const auto index = indexes.first(); + if (!index.isValid()) { + qWarning() << "Failed to preview an attachment: Attachment not found"; + return; + } + + // Set selection to the first + m_ui->attachmentsView->setCurrentIndex(index); + + auto name = m_attachmentsModel->keyByIndex(index); + auto data = m_entryAttachments->value(name); + + PreviewEntryAttachmentsDialog previewDialog(this); + previewDialog.setAttachment({name, data}); + + connect(&previewDialog, SIGNAL(openAttachment(QString)), SLOT(openSelectedAttachments())); + connect(&previewDialog, SIGNAL(saveAttachment(QString)), SLOT(saveSelectedAttachments())); + // Refresh the preview if the attachment changes + connect(m_entryAttachments, + &EntryAttachments::keyModified, + &previewDialog, + [&previewDialog, &name, this](const QString& key) { + if (key == name) { + previewDialog.setAttachment({name, m_entryAttachments->value(name)}); + } + }); + + previewDialog.exec(); + + // Set focus back to the widget to allow keyboard navigation + setFocus(); +} + +void EntryAttachmentsWidget::editSelectedAttachment() +{ + Q_ASSERT(m_entryAttachments); + + const auto selectionModel = m_ui->attachmentsView->selectionModel(); + if (!selectionModel) { + qWarning() << "Failed to edit an attachment: No selection model"; + return; + } + + const auto selectedIndexes = selectionModel->selectedIndexes(); + if (selectedIndexes.isEmpty()) { + qWarning() << "Failed to edit an attachment: No attachment selected"; + return; + } + + const auto index = selectedIndexes.first(); + + if (!index.isValid()) { + qWarning() << "Failed to edit an attachment: Attachment not found"; + return; + } + + // Set selection to the first + m_ui->attachmentsView->setCurrentIndex(index); + + auto name = m_attachmentsModel->keyByIndex(index); + auto data = m_entryAttachments->value(name); + + EditEntryAttachmentsDialog editDialog(this); + editDialog.setAttachment({name, data}); + + if (editDialog.exec() == QDialog::Accepted) { + auto attachment = editDialog.getAttachment(); + + // Edit dialog cannot change the name of the attachment + if (attachment.name == name) { + m_entryAttachments->set(attachment.name, attachment.data); + } + } + + // Set focus back to the widget to allow keyboard navigation + setFocus(); +} + void EntryAttachmentsWidget::removeSelectedAttachments() { Q_ASSERT(m_entryAttachments); @@ -194,12 +341,6 @@ void EntryAttachmentsWidget::removeSelectedAttachments() } } -void EntryAttachmentsWidget::renameSelectedAttachments() -{ - Q_ASSERT(m_entryAttachments); - m_ui->attachmentsView->edit(m_ui->attachmentsView->selectionModel()->selectedIndexes().first()); -} - void EntryAttachmentsWidget::saveSelectedAttachments() { Q_ASSERT(m_entryAttachments); @@ -289,7 +430,7 @@ void EntryAttachmentsWidget::openSelectedAttachments() if (!m_entryAttachments->openAttachment(m_attachmentsModel->keyByIndex(index), &errorMessage)) { const QString filename = m_attachmentsModel->keyByIndex(index); errors.append(QString("%1 - %2").arg(filename, errorMessage)); - }; + } } if (!errors.isEmpty()) { @@ -299,21 +440,38 @@ void EntryAttachmentsWidget::openSelectedAttachments() void EntryAttachmentsWidget::updateButtonsEnabled() { - const bool hasSelection = m_ui->attachmentsView->selectionModel()->hasSelection(); + const auto selectionModel = m_ui->attachmentsView->selectionModel(); + const bool hasSelection = selectionModel && selectionModel->hasSelection(); m_ui->addAttachmentButton->setEnabled(!m_readOnly); m_ui->removeAttachmentButton->setEnabled(hasSelection && !m_readOnly); - m_ui->renameAttachmentButton->setEnabled(hasSelection && !m_readOnly); + + m_ui->editAttachmentButton->setEnabled(hasSelection && !m_readOnly); + if (const auto indexes = selectionModel ? selectionModel->selectedIndexes() : QModelIndexList{}; !indexes.empty()) { + auto mimeType = Tools::getMimeType(m_entryAttachments->value(m_attachmentsModel->keyByIndex(indexes.first()))); + m_ui->editAttachmentButton->setEnabled(hasSelection && !m_readOnly && Tools::isTextMimeType(mimeType)); + } m_ui->saveAttachmentButton->setEnabled(hasSelection); + m_ui->previewAttachmentButton->setEnabled(hasSelection); m_ui->openAttachmentButton->setEnabled(hasSelection); + + updateLinesVisibility(); +} + +void EntryAttachmentsWidget::updateLinesVisibility() +{ + m_ui->editPreviewLine->setVisible(m_buttonsVisible && !m_readOnly); + m_ui->previewRemoveLine->setVisible(m_buttonsVisible && !m_readOnly); } void EntryAttachmentsWidget::updateButtonsVisible() { m_ui->addAttachmentButton->setVisible(m_buttonsVisible && !m_readOnly); + m_ui->editAttachmentButton->setVisible(m_buttonsVisible && !m_readOnly); m_ui->removeAttachmentButton->setVisible(m_buttonsVisible && !m_readOnly); - m_ui->renameAttachmentButton->setVisible(m_buttonsVisible && !m_readOnly); + + updateLinesVisibility(); } bool EntryAttachmentsWidget::insertAttachments(const QStringList& filenames, QString& errorMessage) @@ -391,14 +549,14 @@ bool EntryAttachmentsWidget::eventFilter(QObject* watched, QEvent* e) if (watched == m_ui->attachmentsView->viewport() && !isReadOnly()) { const QEvent::Type eventType = e->type(); if (eventType == QEvent::DragEnter || eventType == QEvent::DragMove) { - QDropEvent* dropEv = static_cast(e); + auto dropEv = static_cast(e); const QMimeData* mimeData = dropEv->mimeData(); if (mimeData->hasUrls()) { dropEv->acceptProposedAction(); return true; } } else if (eventType == QEvent::Drop) { - QDropEvent* dropEv = static_cast(e); + auto dropEv = static_cast(e); const QMimeData* mimeData = dropEv->mimeData(); if (mimeData->hasUrls()) { dropEv->acceptProposedAction(); diff --git a/src/gui/entry/EntryAttachmentsWidget.h b/src/gui/entry/EntryAttachmentsWidget.h index 9d64ed31b..8d82d02d8 100644 --- a/src/gui/entry/EntryAttachmentsWidget.h +++ b/src/gui/entry/EntryAttachmentsWidget.h @@ -37,7 +37,7 @@ class EntryAttachmentsWidget : public QWidget Q_PROPERTY(bool isButtonsVisible READ isButtonsVisible WRITE setButtonsVisible NOTIFY buttonsVisibleChanged) public: explicit EntryAttachmentsWidget(QWidget* parent = nullptr); - ~EntryAttachmentsWidget(); + ~EntryAttachmentsWidget() override; const EntryAttachments* attachments() const; bool isReadOnly() const; @@ -57,8 +57,10 @@ signals: private slots: void insertAttachments(); + void newAttachments(); + void editSelectedAttachment(); + void previewSelectedAttachment(); void removeSelectedAttachments(); - void renameSelectedAttachments(); void saveSelectedAttachments(); void openAttachment(const QModelIndex& index); void openSelectedAttachments(); @@ -67,6 +69,8 @@ private slots: void attachmentModifiedExternally(const QString& key, const QString& filePath); private: + void updateLinesVisibility(); + bool insertAttachments(const QStringList& fileNames, QString& errorMessage); QStringList confirmAttachmentSelection(const QStringList& filenames); diff --git a/src/gui/entry/EntryAttachmentsWidget.ui b/src/gui/entry/EntryAttachmentsWidget.ui index e685813b3..7fd960972 100644 --- a/src/gui/entry/EntryAttachmentsWidget.ui +++ b/src/gui/entry/EntryAttachmentsWidget.ui @@ -6,8 +6,8 @@ 0 0 - 337 - 289 + 332 + 312 @@ -34,11 +34,20 @@ QAbstractItemView::EditKeyPressed|QAbstractItemView::SelectedClicked + + QAbstractItemView::SelectRows + + + false + + + false + - + 0 @@ -60,33 +69,34 @@ Add new attachment
    - Add + Add file… - + false - - Remove selected attachment - - Remove + Edit - + + + Qt::Horizontal + + + + + false - - Rename selected attachment - - Rename + Preview @@ -112,19 +122,45 @@ Save selected attachment to disk - Save + Save… - + + + true + + + Qt::Horizontal + + + + + + + false + + + Remove selected attachment + + + Remove + + + + + Qt::Vertical + + QSizePolicy::Expanding + 20 - 173 + 0 diff --git a/src/gui/entry/EntryAttributesModel.cpp b/src/gui/entry/EntryAttributesModel.cpp index 90ef21bb3..604f9af64 100644 --- a/src/gui/entry/EntryAttributesModel.cpp +++ b/src/gui/entry/EntryAttributesModel.cpp @@ -24,6 +24,7 @@ EntryAttributesModel::EntryAttributesModel(QObject* parent) , m_entryAttributes(nullptr) , m_nextRenameDataChange(false) { + m_collator.setNumericMode(true); } void EntryAttributesModel::setEntryAttributes(EntryAttributes* entryAttributes) @@ -80,14 +81,14 @@ QVariant EntryAttributesModel::headerData(int section, Qt::Orientation orientati if ((orientation == Qt::Horizontal) && (role == Qt::DisplayRole) && (section == 0)) { return tr("Name"); } else { - return QVariant(); + return {}; } } QVariant EntryAttributesModel::data(const QModelIndex& index, int role) const { if (!index.isValid() || (role != Qt::DisplayRole && role != Qt::EditRole)) { - return QVariant(); + return {}; } return m_attributes.at(index.row()); @@ -124,7 +125,7 @@ QModelIndex EntryAttributesModel::indexByKey(const QString& key) const int row = m_attributes.indexOf(key); if (row == -1) { - return QModelIndex(); + return {}; } else { return index(row, 0); } @@ -133,7 +134,7 @@ QModelIndex EntryAttributesModel::indexByKey(const QString& key) const QString EntryAttributesModel::keyByIndex(const QModelIndex& index) const { if (!index.isValid()) { - return QString(); + return {}; } else { return m_attributes.at(index.row()); } @@ -150,7 +151,7 @@ void EntryAttributesModel::attributeAboutToAdd(const QString& key) { QList rows = m_attributes; rows.append(key); - std::sort(rows.begin(), rows.end()); + std::sort(rows.begin(), rows.end(), m_collator); int row = rows.indexOf(key); beginInsertRows(QModelIndex(), row, row); } @@ -180,7 +181,7 @@ void EntryAttributesModel::attributeAboutToRename(const QString& oldKey, const Q QList rows = m_attributes; rows.removeOne(oldKey); rows.append(newKey); - std::sort(rows.begin(), rows.end()); + std::sort(rows.begin(), rows.end(), m_collator); int newRow = rows.indexOf(newKey); if (newRow > oldRow) { newRow++; @@ -232,4 +233,5 @@ void EntryAttributesModel::updateAttributes() m_attributes.append(key); } } + std::sort(m_attributes.begin(), m_attributes.end(), m_collator); } diff --git a/src/gui/entry/EntryAttributesModel.h b/src/gui/entry/EntryAttributesModel.h index 7d613c1f0..650426c32 100644 --- a/src/gui/entry/EntryAttributesModel.h +++ b/src/gui/entry/EntryAttributesModel.h @@ -19,6 +19,7 @@ #define KEEPASSX_ENTRYATTRIBUTESMODEL_H #include +#include class EntryAttributes; @@ -55,6 +56,7 @@ private: EntryAttributes* m_entryAttributes; QList m_attributes; bool m_nextRenameDataChange; + QCollator m_collator; }; #endif // KEEPASSX_ENTRYATTRIBUTESMODEL_H diff --git a/src/gui/entry/EntryHistoryModel.cpp b/src/gui/entry/EntryHistoryModel.cpp index 563ab12ce..57cac8d9f 100644 --- a/src/gui/entry/EntryHistoryModel.cpp +++ b/src/gui/entry/EntryHistoryModel.cpp @@ -26,6 +26,7 @@ EntryHistoryModel::EntryHistoryModel(QObject* parent) : QAbstractTableModel(parent) + , m_systemLocale(QLocale::system()) { } @@ -67,7 +68,7 @@ QVariant EntryHistoryModel::data(const QModelIndex& index, int role) const switch (index.column()) { case 0: if (role == Qt::DisplayRole) { - return lastModified.toString(Qt::SystemLocaleShortDate); + return m_systemLocale.toString(lastModified, QLocale::ShortFormat); } else { return lastModified; } diff --git a/src/gui/entry/EntryHistoryModel.h b/src/gui/entry/EntryHistoryModel.h index 21897ec07..101e4ac93 100644 --- a/src/gui/entry/EntryHistoryModel.h +++ b/src/gui/entry/EntryHistoryModel.h @@ -19,6 +19,7 @@ #define KEEPASSX_ENTRYHISTORYMODEL_H #include +#include class Entry; @@ -45,6 +46,7 @@ public: private: void calculateHistoryModifications(); + QLocale m_systemLocale; QList m_historyEntries; QList m_deletedHistoryEntries; QStringList m_historyModifications; diff --git a/src/gui/entry/EntryModel.cpp b/src/gui/entry/EntryModel.cpp index 95c9cefb2..218da6ca8 100644 --- a/src/gui/entry/EntryModel.cpp +++ b/src/gui/entry/EntryModel.cpp @@ -21,6 +21,7 @@ #include #include +#include "core/Clock.h" #include "core/Entry.h" #include "core/Group.h" #include "core/Metadata.h" @@ -36,7 +37,6 @@ EntryModel::EntryModel(QObject* parent) : QAbstractTableModel(parent) , m_group(nullptr) , HiddenContentDisplay(QString("\u25cf").repeated(6)) - , DateFormat(Qt::DefaultLocaleShortDate) { connect(config(), &Config::changed, this, &EntryModel::onConfigChanged); } @@ -116,13 +116,13 @@ int EntryModel::columnCount(const QModelIndex& parent) const return 0; } - return 15; + return 17; } QVariant EntryModel::data(const QModelIndex& index, int role) const { if (!index.isValid()) { - return QVariant(); + return {}; } Entry* entry = entryFromIndex(index); @@ -136,6 +136,11 @@ QVariant EntryModel::data(const QModelIndex& index, int role) const return entry->group()->name(); } break; + case ParentGroupPath: + if (entry->group()) { + return entry->group()->fullPath(); + } + break; case Title: result = entry->resolveMultiplePlaceholders(entry->title()); if (attr->isReference(EntryAttributes::TitleKey)) { @@ -189,18 +194,17 @@ QVariant EntryModel::data(const QModelIndex& index, int role) const return result; case Expires: // Display either date of expiry or 'Never' - result = entry->timeInfo().expires() - ? entry->timeInfo().expiryTime().toLocalTime().toString(EntryModel::DateFormat) - : tr("Never"); + result = entry->timeInfo().expires() ? Clock::toString(entry->timeInfo().expiryTime().toLocalTime()) + : tr("Never"); return result; case Created: - result = entry->timeInfo().creationTime().toLocalTime().toString(EntryModel::DateFormat); + result = Clock::toString(entry->timeInfo().creationTime().toLocalTime()); return result; case Modified: - result = entry->timeInfo().lastModificationTime().toLocalTime().toString(EntryModel::DateFormat); + result = Clock::toString(entry->timeInfo().lastModificationTime().toLocalTime()); return result; case Accessed: - result = entry->timeInfo().lastAccessTime().toLocalTime().toString(EntryModel::DateFormat); + result = Clock::toString(entry->timeInfo().lastAccessTime().toLocalTime()); return result; case Attachments: { // Display comma-separated list of attachments @@ -230,6 +234,13 @@ QVariant EntryModel::data(const QModelIndex& index, int role) const return result; } + case Color: + QColor backgroundColor; + backgroundColor.setNamedColor(entry->backgroundColor()); + if (backgroundColor.isValid()) { + result = "▍"; + return result; + } } } else if (role == Qt::UserRole) { // Qt::UserRole is used as sort role, see EntryView::EntryView() switch (index.column()) { @@ -244,8 +255,13 @@ QVariant EntryModel::data(const QModelIndex& index, int role) const return 0; } case Expires: + return entry->timeInfo().expires() ? entry->timeInfo().expiryTime() // There seems to be no better way of expressing 'infinity' - return entry->timeInfo().expires() ? entry->timeInfo().expiryTime() : QDateTime(QDate(9999, 1, 1)); +#if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0) + : QDate(9999, 1, 1).startOfDay(); +#else + : QDateTime(QDate(9999, 1, 1)); +#endif case Created: return entry->timeInfo().creationTime(); case Modified: @@ -281,29 +297,35 @@ QVariant EntryModel::data(const QModelIndex& index, int role) const break; case Totp: if (entry->hasTotp()) { - return icons()->icon("totp"); + return entry->hasValidTotp() ? icons()->icon("totp") : icons()->icon("totp-invalid"); } break; case PasswordStrength: if (!entry->password().isEmpty() && !entry->excludeFromReports()) { + QString iconName = "lock-question"; StateColorPalette statePalette; QColor color = statePalette.color(StateColorPalette::Error); switch (entry->passwordHealth()->quality()) { case PasswordHealth::Quality::Bad: case PasswordHealth::Quality::Poor: + iconName = "lock-open-alert"; color = statePalette.color(StateColorPalette::HealthCritical); break; case PasswordHealth::Quality::Weak: + iconName = "lock-open"; color = statePalette.color(StateColorPalette::HealthBad); break; case PasswordHealth::Quality::Good: case PasswordHealth::Quality::Excellent: + iconName = "lock"; color = statePalette.color(StateColorPalette::HealthExcellent); break; } - return color; + if (color.isValid()) { + return icons()->icon(iconName, true, color); + } } break; } @@ -314,6 +336,15 @@ QVariant EntryModel::data(const QModelIndex& index, int role) const } return font; } else if (role == Qt::ForegroundRole) { + + if (index.column() == Color) { + QColor backgroundColor; + backgroundColor.setNamedColor(entry->backgroundColor()); + if (backgroundColor.isValid()) { + return backgroundColor; + } + } + QColor foregroundColor; foregroundColor.setNamedColor(entry->foregroundColor()); if (entry->hasReferences()) { @@ -327,10 +358,12 @@ QVariant EntryModel::data(const QModelIndex& index, int role) const return QVariant(foregroundColor); } } else if (role == Qt::BackgroundRole) { - QColor backgroundColor; - backgroundColor.setNamedColor(entry->backgroundColor()); - if (backgroundColor.isValid()) { - return QVariant(backgroundColor); + if (m_backgroundColorVisible) { + QColor backgroundColor; + backgroundColor.setNamedColor(entry->backgroundColor()); + if (backgroundColor.isValid()) { + return QVariant(backgroundColor); + } } } else if (role == Qt::ToolTipRole) { if (index.column() == PasswordStrength && !entry->password().isEmpty() && !entry->excludeFromReports()) { @@ -338,7 +371,7 @@ QVariant EntryModel::data(const QModelIndex& index, int role) const } } - return QVariant(); + return {}; } QVariant EntryModel::headerData(int section, Qt::Orientation orientation, int role) const @@ -349,6 +382,8 @@ QVariant EntryModel::headerData(int section, Qt::Orientation orientation, int ro switch (section) { case ParentGroup: return tr("Group"); + case ParentGroupPath: + return tr("Group Path"); case Title: return tr("Title"); case Username: @@ -386,6 +421,8 @@ QVariant EntryModel::headerData(int section, Qt::Orientation orientation, int ro switch (section) { case ParentGroup: return tr("Group name"); + case ParentGroupPath: + return tr("Group Path"); case Title: return tr("Entry title"); case Username: @@ -414,6 +451,8 @@ QVariant EntryModel::headerData(int section, Qt::Orientation orientation, int ro return tr("Has attachments"); case Totp: return tr("Has TOTP"); + case Color: + return tr("Background Color"); } } @@ -452,7 +491,7 @@ QMimeData* EntryModel::mimeData(const QModelIndexList& indexes) const return nullptr; } - QMimeData* data = new QMimeData(); + auto data = new QMimeData(); QByteArray encoded; QDataStream stream(&encoded, QIODevice::WriteOnly); @@ -596,3 +635,7 @@ void EntryModel::makeConnections(const Group* group) connect(group, SIGNAL(entryMovedDown()), SLOT(entryMovedDown())); connect(group, SIGNAL(entryDataChanged(Entry*)), SLOT(entryDataChanged(Entry*))); } +void EntryModel::setBackgroundColorVisible(bool visible) +{ + m_backgroundColorVisible = visible; +} diff --git a/src/gui/entry/EntryModel.h b/src/gui/entry/EntryModel.h index 8e79be384..7b7f17a1f 100644 --- a/src/gui/entry/EntryModel.h +++ b/src/gui/entry/EntryModel.h @@ -48,7 +48,9 @@ public: Attachments = 11, Totp = 12, Size = 13, - PasswordStrength = 14 + PasswordStrength = 14, + Color = 15, + ParentGroupPath = 16 }; explicit EntryModel(QObject* parent = nullptr); @@ -67,6 +69,7 @@ public: void setGroup(Group* group); void setEntries(const QList& entries); + void setBackgroundColorVisible(bool visible); private slots: void entryAboutToAdd(Entry* entry); @@ -85,13 +88,13 @@ private: void severConnections(); void makeConnections(const Group* group); + bool m_backgroundColorVisible = true; Group* m_group; QList m_entries; QList m_orgEntries; QSet m_allGroups; const QString HiddenContentDisplay; - const Qt::DateFormat DateFormat; }; #endif // KEEPASSX_ENTRYMODEL_H diff --git a/src/gui/entry/EntryURLModel.cpp b/src/gui/entry/EntryURLModel.cpp index 046fbee61..d0201562b 100644 --- a/src/gui/entry/EntryURLModel.cpp +++ b/src/gui/entry/EntryURLModel.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2023 KeePassXC Team + * Copyright (C) 2025 KeePassXC Team * Copyright (C) 2012 Felix Geyer * * This program is free software: you can redistribute it and/or modify @@ -20,8 +20,8 @@ #include "browser/BrowserService.h" #include "core/EntryAttributes.h" -#include "core/UrlTools.h" #include "gui/Icons.h" +#include "gui/UrlTools.h" #include "gui/styles/StateColorPalette.h" EntryURLModel::EntryURLModel(QObject* parent) @@ -67,7 +67,7 @@ QVariant EntryURLModel::data(const QModelIndex& index, int role) const } const auto value = m_entryAttributes->value(key); - const auto urlValid = urlTools()->isUrlValid(value); + const auto urlValid = urlTools()->isUrlValid(value, true); // Check for duplicate URLs in the attribute list. Excludes the current key/value from the comparison. auto customAttributeKeys = m_entryAttributes->customKeys().filter(EntryAttributes::AdditionalUrlAttribute); diff --git a/src/gui/entry/EntryURLModel.h b/src/gui/entry/EntryURLModel.h index 2801f9ffe..8fd5ef119 100644 --- a/src/gui/entry/EntryURLModel.h +++ b/src/gui/entry/EntryURLModel.h @@ -46,7 +46,6 @@ public: explicit EntryURLModel(QObject* parent = nullptr); void setEntryAttributes(EntryAttributes* entryAttributes); - void insertRow(const QString& key, const QString& value); void setEntryUrl(const QString& entryUrl); bool setData(const QModelIndex& index, const QVariant& value, int role = Qt::EditRole) override; QVariant data(const QModelIndex& index, int role) const override; diff --git a/src/gui/entry/EntryView.cpp b/src/gui/entry/EntryView.cpp index 419a08d75..5fdad83b3 100644 --- a/src/gui/entry/EntryView.cpp +++ b/src/gui/entry/EntryView.cpp @@ -336,6 +336,7 @@ bool EntryView::setViewState(const QByteArray& state) bool status = header()->restoreState(state); resetFixedColumns(); m_columnsNeedRelayout = state.isEmpty(); + onHeaderChanged(); return status; } @@ -376,6 +377,9 @@ void EntryView::toggleColumnVisibility(QAction* action) // least one visible column remains, as the table header will disappear // entirely when all columns are hidden int columnIndex = action->data().toInt(); + if (columnIndex == EntryModel::Color) { + m_model->setBackgroundColorVisible(!action->isChecked()); + } if (action->isChecked()) { header()->showSection(columnIndex); if (header()->sectionSize(columnIndex) == 0) { @@ -447,6 +451,8 @@ void EntryView::resetFixedColumns() header()->resizeSection(col, width); } } + header()->setMinimumSectionSize(1); + header()->resizeSection(EntryModel::Color, ICON_ONLY_SECTION_SIZE); } /** @@ -475,6 +481,9 @@ void EntryView::resetViewToDefaults() header()->hideSection(EntryModel::Attachments); header()->hideSection(EntryModel::Size); header()->hideSection(EntryModel::PasswordStrength); + header()->hideSection(EntryModel::Color); + header()->hideSection(EntryModel::ParentGroupPath); + onHeaderChanged(); // Reset column order to logical indices for (int i = 0; i < header()->count(); ++i) { @@ -502,6 +511,11 @@ void EntryView::resetViewToDefaults() } } +void EntryView::onHeaderChanged() +{ + m_model->setBackgroundColorVisible(isColumnHidden(EntryModel::Color)); +} + void EntryView::showEvent(QShowEvent* event) { QTreeView::showEvent(event); @@ -557,17 +571,10 @@ void EntryView::startDrag(Qt::DropActions supportedActions) // Grab the screen pixel ratio where the window resides // TODO: Use direct call to screen() when moving to Qt 6 -#if QT_VERSION >= QT_VERSION_CHECK(5, 10, 0) auto screen = QGuiApplication::screenAt(window()->geometry().center()); if (!screen) { screen = QGuiApplication::primaryScreen(); } -#else - auto screen = QGuiApplication::primaryScreen(); - if (windowHandle()) { - screen = windowHandle()->screen(); - } -#endif auto pixelRatio = screen->devicePixelRatio(); diff --git a/src/gui/entry/EntryView.h b/src/gui/entry/EntryView.h index 3a0cc1d60..759097b34 100644 --- a/src/gui/entry/EntryView.h +++ b/src/gui/entry/EntryView.h @@ -76,6 +76,7 @@ private slots: private: void resetFixedColumns(); bool isColumnHidden(int logicalIndex); + void onHeaderChanged(); EntryModel* const m_model; SortFilterHideProxyModel* const m_sortModel; diff --git a/src/gui/entry/PreviewEntryAttachmentsDialog.cpp b/src/gui/entry/PreviewEntryAttachmentsDialog.cpp new file mode 100644 index 000000000..62be2bd34 --- /dev/null +++ b/src/gui/entry/PreviewEntryAttachmentsDialog.cpp @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2025 KeePassXC Team + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 or (at your option) + * version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "PreviewEntryAttachmentsDialog.h" +#include "ui_PreviewEntryAttachmentsDialog.h" + +#include +#include +#include +#include + +PreviewEntryAttachmentsDialog::PreviewEntryAttachmentsDialog(QWidget* parent) + : QDialog(parent) + , m_ui(new Ui::PreviewEntryAttachmentsDialog) +{ + m_ui->setupUi(this); + + // Disable the help button in the title bar + setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint); + + // Initialize dialog buttons + m_ui->dialogButtons->setStandardButtons(QDialogButtonBox::Close | QDialogButtonBox::Open | QDialogButtonBox::Save); + auto closeButton = m_ui->dialogButtons->button(QDialogButtonBox::Close); + closeButton->setDefault(true); + + auto saveButton = m_ui->dialogButtons->button(QDialogButtonBox::Save); + saveButton->setText(tr("Save…")); + + connect(m_ui->dialogButtons, &QDialogButtonBox::rejected, this, &PreviewEntryAttachmentsDialog::reject); + connect(m_ui->dialogButtons, &QDialogButtonBox::clicked, [this](QAbstractButton* button) { + auto pressedButton = m_ui->dialogButtons->standardButton(button); + + const auto attachment = m_ui->attachmentWidget->getAttachment(); + if (pressedButton == QDialogButtonBox::Open) { + emit openAttachment(attachment.name); + } else if (pressedButton == QDialogButtonBox::Save) { + emit saveAttachment(attachment.name); + } + }); +} + +PreviewEntryAttachmentsDialog::~PreviewEntryAttachmentsDialog() = default; + +void PreviewEntryAttachmentsDialog::setAttachment(attachments::Attachment attachment) +{ + setWindowTitle(tr("Preview: %1").arg(attachment.name)); + + m_ui->attachmentWidget->openAttachment(std::move(attachment), attachments::OpenMode::ReadOnly); +} diff --git a/src/gui/entry/PreviewEntryAttachmentsDialog.h b/src/gui/entry/PreviewEntryAttachmentsDialog.h new file mode 100644 index 000000000..cee23ea13 --- /dev/null +++ b/src/gui/entry/PreviewEntryAttachmentsDialog.h @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2025 KeePassXC Team + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 or (at your option) + * version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once + +#include "attachments/AttachmentTypes.h" + +#include + +#include +#include + +namespace Ui +{ + class PreviewEntryAttachmentsDialog; +} + +class PreviewEntryAttachmentsDialog : public QDialog +{ + Q_OBJECT + +public: + explicit PreviewEntryAttachmentsDialog(QWidget* parent = nullptr); + ~PreviewEntryAttachmentsDialog() override; + + void setAttachment(attachments::Attachment attachment); + +signals: + void openAttachment(const QString& name); + void saveAttachment(const QString& name); + +private: + QScopedPointer m_ui; +}; diff --git a/src/gui/entry/PreviewEntryAttachmentsDialog.ui b/src/gui/entry/PreviewEntryAttachmentsDialog.ui new file mode 100644 index 000000000..d7f8fd31c --- /dev/null +++ b/src/gui/entry/PreviewEntryAttachmentsDialog.ui @@ -0,0 +1,58 @@ + + + PreviewEntryAttachmentsDialog + + + + 0 + 0 + 557 + 454 + + + + Form + + + + 6 + + + 6 + + + 6 + + + 6 + + + + + + 0 + 0 + + + + + + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + + AttachmentWidget + QWidget +
    gui/entry/attachments/AttachmentWidget.h
    + 1 +
    +
    + + +
    diff --git a/src/core/ListDeleter.h b/src/gui/entry/attachments/AttachmentTypes.h similarity index 63% rename from src/core/ListDeleter.h rename to src/gui/entry/attachments/AttachmentTypes.h index 6f289546f..9d63bc23e 100644 --- a/src/core/ListDeleter.h +++ b/src/gui/entry/attachments/AttachmentTypes.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012 Felix Geyer + * Copyright (C) 2025 KeePassXC Team * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -15,25 +15,23 @@ * along with this program. If not, see . */ -#ifndef KEEPASSX_LISTDELETER_H -#define KEEPASSX_LISTDELETER_H +#pragma once -#include +#include +#include -template class ListDeleter +namespace attachments { -public: - inline explicit ListDeleter(QList* list) - : m_list(list) + struct Attachment { - } - inline ~ListDeleter() + QString name; + QByteArray data; + }; + + enum class OpenMode { - qDeleteAll(*m_list); - } + ReadOnly, + ReadWrite + }; -private: - QList* m_list; -}; - -#endif // KEEPASSX_LISTDELETER_H +} // namespace attachments diff --git a/src/gui/entry/attachments/AttachmentWidget.cpp b/src/gui/entry/attachments/AttachmentWidget.cpp new file mode 100644 index 000000000..f68df2d00 --- /dev/null +++ b/src/gui/entry/attachments/AttachmentWidget.cpp @@ -0,0 +1,89 @@ +/* + * Copyright (C) 2025 KeePassXC Team + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 or (at your option) + * version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "AttachmentWidget.h" + +#include "ImageAttachmentsWidget.h" +#include "TextAttachmentsWidget.h" + +#include + +#include +#include + +AttachmentWidget::AttachmentWidget(QWidget* parent) + : QWidget(parent) +{ + setWindowTitle(tr("Attachment Viewer")); + + auto verticalLayout = new QVBoxLayout(this); + verticalLayout->setSpacing(0); + verticalLayout->setObjectName(QString::fromUtf8("verticalLayout")); + verticalLayout->setContentsMargins(0, 0, 0, 0); + verticalLayout->setAlignment(Qt::AlignCenter); +} + +AttachmentWidget::~AttachmentWidget() = default; + +void AttachmentWidget::openAttachment(attachments::Attachment attachment, attachments::OpenMode mode) +{ + m_attachment = std::move(attachment); + m_mode = mode; + + updateUi(); +} + +void AttachmentWidget::updateUi() +{ + auto type = Tools::getMimeType(m_attachment.data); + + if (m_attachmentWidget) { + layout()->removeWidget(m_attachmentWidget); + m_attachmentWidget->deleteLater(); + } + + if (Tools::isTextMimeType(type)) { + auto widget = new TextAttachmentsWidget(this); + widget->openAttachment(m_attachment, m_mode); + + m_attachmentWidget = widget; + } else if (type == Tools::MimeType::Image) { + auto widget = new ImageAttachmentsWidget(this); + widget->openAttachment(m_attachment, m_mode); + + m_attachmentWidget = widget; + } else { + auto label = new QLabel(tr("Unknown attachment type"), this); + label->setAlignment(Qt::AlignCenter); + + m_attachmentWidget = label; + } + + Q_ASSERT(m_attachmentWidget); + m_attachmentWidget->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); + layout()->addWidget(m_attachmentWidget); +} + +attachments::Attachment AttachmentWidget::getAttachment() const +{ + // Text attachments can be edited at this time so pass this call forward + if (auto textWidget = qobject_cast(m_attachmentWidget)) { + return textWidget->getAttachment(); + } + + return m_attachment; +} diff --git a/src/gui/entry/attachments/AttachmentWidget.h b/src/gui/entry/attachments/AttachmentWidget.h new file mode 100644 index 000000000..73dd5b2b5 --- /dev/null +++ b/src/gui/entry/attachments/AttachmentWidget.h @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2025 KeePassXC Team + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 or (at your option) + * version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once + +#include "AttachmentTypes.h" + +#include + +#include +#include +#include + +namespace Ui +{ + class AttachmentWidget; +} + +/** + * @brief The AttachmentWidget class provides a way to manage attachments in a GUI application. + * + */ +class AttachmentWidget : public QWidget +{ + Q_OBJECT + +public: + explicit AttachmentWidget(QWidget* parent = nullptr); + ~AttachmentWidget() override; + + /** + * @brief Opens an attachment in the specified mode. + * + * @param attachment - The attachment to be opened. + * @param mode - The mode in which to open the attachment (read-only or read-write). + */ + void openAttachment(attachments::Attachment attachment, attachments::OpenMode mode); + + /** + * @brief Get the current attachment. + * + * @return Attachment - The current attachment. + */ + attachments::Attachment getAttachment() const; + +private: + void updateUi(); + + QPointer m_attachmentWidget; + + attachments::Attachment m_attachment; + attachments::OpenMode m_mode; +}; diff --git a/src/gui/entry/attachments/ImageAttachmentsView.cpp b/src/gui/entry/attachments/ImageAttachmentsView.cpp new file mode 100644 index 000000000..fea7a2d5f --- /dev/null +++ b/src/gui/entry/attachments/ImageAttachmentsView.cpp @@ -0,0 +1,98 @@ +/* + * Copyright (C) 2025 KeePassXC Team + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 or (at your option) + * version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "ImageAttachmentsView.h" + +#include +#include + +#include + +ImageAttachmentsView::ImageAttachmentsView(QWidget* parent) + : QGraphicsView(parent) +{ +} + +void ImageAttachmentsView::wheelEvent(QWheelEvent* event) +{ + if (event->modifiers() == Qt::ControlModifier) { + emit ctrlWheelEvent(event); + return; + } + + QGraphicsView::wheelEvent(event); +} + +void ImageAttachmentsView::resizeEvent(QResizeEvent* event) +{ + QGraphicsView::resizeEvent(event); + + if (m_autoFitInView) { + fitSceneInView(); + } +} + +void ImageAttachmentsView::showEvent(QShowEvent* event) +{ + if (m_autoFitInView) { + fitSceneInView(); + } + + QGraphicsView::showEvent(event); +} + +void ImageAttachmentsView::fitSceneInView() +{ + if (auto scene = ImageAttachmentsView::scene()) { + ImageAttachmentsView::fitInView(scene->itemsBoundingRect(), Qt::KeepAspectRatio); + } +} + +void ImageAttachmentsView::enableAutoFitInView() +{ + m_autoFitInView = true; + fitSceneInView(); +} + +void ImageAttachmentsView::disableAutoFitInView() +{ + m_autoFitInView = false; +} + +bool ImageAttachmentsView::isAutoFitInViewActivated() const +{ + return m_autoFitInView; +} + +double ImageAttachmentsView::calculateFitInViewFactor() const +{ + auto viewPort = viewport(); + if (auto currentScene = scene(); currentScene && viewPort) { + const auto itemsRect = currentScene->itemsBoundingRect().size(); + + // If the image rect is empty + if (itemsRect.isEmpty()) { + return std::numeric_limits::quiet_NaN(); + } + + const auto viewPortSize = viewPort->size(); + // Calculate the zoom factor based on the current size and the image rect + return std::min(viewPortSize.width() / itemsRect.width(), viewPortSize.height() / itemsRect.height()); + } + + return std::numeric_limits::quiet_NaN(); +} diff --git a/src/gui/entry/attachments/ImageAttachmentsView.h b/src/gui/entry/attachments/ImageAttachmentsView.h new file mode 100644 index 000000000..3fa4f76b6 --- /dev/null +++ b/src/gui/entry/attachments/ImageAttachmentsView.h @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2025 KeePassXC Team + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 or (at your option) + * version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once + +#include + +class ImageAttachmentsView : public QGraphicsView +{ + Q_OBJECT +public: + explicit ImageAttachmentsView(QWidget* parent = nullptr); + + void enableAutoFitInView(); + void disableAutoFitInView(); + bool isAutoFitInViewActivated() const; + + double calculateFitInViewFactor() const; + +signals: + void ctrlWheelEvent(QWheelEvent* event); + +protected: + void wheelEvent(QWheelEvent* event) override; + void showEvent(QShowEvent* event) override; + void resizeEvent(QResizeEvent* event) override; + +private: + void fitSceneInView(); + + bool m_autoFitInView = false; +}; diff --git a/src/gui/entry/attachments/ImageAttachmentsWidget.cpp b/src/gui/entry/attachments/ImageAttachmentsWidget.cpp new file mode 100644 index 000000000..3d547433c --- /dev/null +++ b/src/gui/entry/attachments/ImageAttachmentsWidget.cpp @@ -0,0 +1,258 @@ +/* + * Copyright (C) 2025 KeePassXC Team + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 or (at your option) + * version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "ImageAttachmentsWidget.h" + +#include "ui_ImageAttachmentsWidget.h" + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +namespace +{ + // Predefined zoom levels must be in ascending order + constexpr std::array ZoomList = {0.25, 0.5, 0.75, 1.0, 2.0}; + constexpr double WheelZoomStep = 1.1; + + const QString FitText = QObject::tr("Fit"); + + QString formatZoomText(double zoomFactor) + { + return QString("%1%").arg(QString::number(zoomFactor * 100, 'f', 0)); + } + + double parseZoomText(const QString& zoomText) + { + auto zoomTextTrimmed = zoomText.trimmed(); + + if (auto percentIndex = zoomTextTrimmed.indexOf('%'); percentIndex != -1) { + // Remove the '%' character and parse the number + zoomTextTrimmed = zoomTextTrimmed.left(percentIndex).trimmed(); + } + + bool ok; + double zoomFactor = zoomTextTrimmed.toDouble(&ok); + if (!ok) { + qWarning() << "Failed to parse zoom text:" << zoomText; + return std::numeric_limits::quiet_NaN(); + } + return zoomFactor / 100.0; + } + +} // namespace + +ImageAttachmentsWidget::ImageAttachmentsWidget(QWidget* parent) + : QWidget(parent) + , m_ui(new Ui::ImageAttachmentsWidget) +{ + m_ui->setupUi(this); + + m_scene = new QGraphicsScene(this); + m_ui->imagesView->setScene(m_scene); + m_ui->imagesView->setDragMode(QGraphicsView::ScrollHandDrag); + m_ui->imagesView->setHorizontalScrollBarPolicy(Qt::ScrollBarPolicy::ScrollBarAlwaysOff); + m_ui->imagesView->setVerticalScrollBarPolicy(Qt::ScrollBarPolicy::ScrollBarAlwaysOff); + + connect(m_ui->imagesView, &ImageAttachmentsView::ctrlWheelEvent, this, &ImageAttachmentsWidget::onWheelZoomEvent); + + static_assert(ZoomList.size() > 0, "ZoomList must not be empty"); + static_assert(ZoomList.front() < ZoomList.back(), "ZoomList must be in ascending order"); + m_zoomHelper = new ZoomHelper(1.0, WheelZoomStep, ZoomList.front(), ZoomList.back(), this); + connect(m_zoomHelper, &ZoomHelper::zoomChanged, this, &ImageAttachmentsWidget::onZoomFactorChanged); + + initZoomComboBox(); +} + +ImageAttachmentsWidget::~ImageAttachmentsWidget() = default; + +void ImageAttachmentsWidget::initZoomComboBox() +{ + m_ui->zoomComboBox->clear(); + + auto textWidth = m_ui->zoomComboBox->fontMetrics().horizontalAdvance(FitText); + + m_ui->zoomComboBox->addItem(FitText, 0.0); + + for (const auto& zoom : ZoomList) { + auto zoomText = formatZoomText(zoom); + textWidth = std::max(textWidth, m_ui->zoomComboBox->fontMetrics().horizontalAdvance(zoomText)); + + m_ui->zoomComboBox->addItem(zoomText, zoom); + } + + constexpr int minWidth = 50; + m_ui->zoomComboBox->setMinimumWidth(textWidth + minWidth); + + connect(m_ui->zoomComboBox, &QComboBox::currentTextChanged, this, &ImageAttachmentsWidget::onZoomChanged); + + connect(m_ui->zoomComboBox->lineEdit(), &QLineEdit::editingFinished, [this]() { + onZoomChanged(m_ui->zoomComboBox->lineEdit()->text()); + }); + + // Fit by default + m_ui->zoomComboBox->setCurrentIndex(m_ui->zoomComboBox->findData(0.0)); + onZoomChanged(m_ui->zoomComboBox->currentText()); +} + +void ImageAttachmentsWidget::onWheelZoomEvent(QWheelEvent* event) +{ + m_ui->imagesView->disableAutoFitInView(); + + auto finInViewFactor = m_ui->imagesView->calculateFitInViewFactor(); + // Limit the fit-in-view factor to a maximum of 100% + m_zoomHelper->setMinZoomOutFactor(std::isnan(finInViewFactor) ? 1.0 : std::min(finInViewFactor, 1.0)); + + event->angleDelta().y() > 0 ? m_zoomHelper->zoomIn() : m_zoomHelper->zoomOut(); +} + +void ImageAttachmentsWidget::onZoomFactorChanged(double zoomFactor) +{ + if (m_ui->imagesView->isAutoFitInViewActivated()) { + return; + } + + m_ui->imagesView->setTransform(QTransform::fromScale(zoomFactor, zoomFactor)); + + // Update the zoom combo box to reflect the current zoom factor + if (!m_ui->zoomComboBox->lineEdit()->hasFocus()) { + m_ui->zoomComboBox->setCurrentText(formatZoomText(zoomFactor)); + } +} + +void ImageAttachmentsWidget::onZoomChanged(const QString& zoomText) +{ + auto zoomFactor = 1.0; + + if (zoomText == FitText) { + m_ui->imagesView->enableAutoFitInView(); + + zoomFactor = std::min(m_ui->imagesView->calculateFitInViewFactor(), zoomFactor); + } else { + zoomFactor = parseZoomText(zoomText); + if (!std::isnan(zoomFactor)) { + m_ui->imagesView->disableAutoFitInView(); + } + } + + if (std::isnan(zoomFactor)) { + return; + } + + m_zoomHelper->setZoomFactor(zoomFactor); +} + +void ImageAttachmentsWidget::openAttachment(attachments::Attachment attachment, attachments::OpenMode mode) +{ + m_attachment = std::move(attachment); + + if (mode == attachments::OpenMode::ReadWrite) { + qWarning() << "Read-write mode is not supported for image attachments"; + } + + loadImage(); +} + +void ImageAttachmentsWidget::loadImage() +{ + QPixmap pixmap{}; + pixmap.loadFromData(m_attachment.data); + if (pixmap.isNull()) { + qWarning() << "Failed to load image from data"; + return; + } + + m_scene->clear(); + m_scene->addPixmap(std::move(pixmap)); +} + +attachments::Attachment ImageAttachmentsWidget::getAttachment() const +{ + return m_attachment; +} + +// Zoom helper +ZoomHelper::ZoomHelper(double zoomFactor, double step, double min, double max, QObject* parent) + : QObject(parent) + , m_step(step) + , m_minZoomOut(min) + , m_maxZoomIn(max) +{ + Q_ASSERT(!std::isnan(step) && step > 0); + Q_ASSERT(!std::isnan(zoomFactor)); + Q_ASSERT(!std::isnan(min)); + Q_ASSERT(!std::isnan(max)); + Q_ASSERT(min < max); + + setZoomFactor(zoomFactor); +} + +void ZoomHelper::zoomIn() +{ + const auto newZoomFactor = m_zoomFactor * m_step; + setZoomFactor(std::isgreater(newZoomFactor, m_maxZoomIn) ? m_zoomFactor : newZoomFactor); +} + +void ZoomHelper::zoomOut() +{ + const auto newZoomFactor = m_zoomFactor / m_step; + setZoomFactor(std::isless(newZoomFactor, m_minZoomOut) ? m_zoomFactor : newZoomFactor); +} + +void ZoomHelper::setZoomFactor(double zoomFactor) +{ + if (std::isnan(zoomFactor)) { + qWarning() << "Failed to set NaN zoom factor"; + return; + } + + auto oldValue = std::exchange(m_zoomFactor, zoomFactor); + if (std::isless(oldValue, m_zoomFactor) || std::isgreater(oldValue, m_zoomFactor)) { + Q_EMIT zoomChanged(m_zoomFactor); + } +} + +double ZoomHelper::getZoomFactor() const +{ + return m_zoomFactor; +} + +void ZoomHelper::setMinZoomOutFactor(double zoomFactor) +{ + if (std::isgreater(zoomFactor, m_maxZoomIn)) { + std::swap(m_maxZoomIn, zoomFactor); + } + + m_minZoomOut = zoomFactor; +} + +void ZoomHelper::setMaxZoomInFactor(double zoomFactor) +{ + if (std::isless(zoomFactor, m_minZoomOut)) { + std::swap(m_minZoomOut, zoomFactor); + } + + m_maxZoomIn = zoomFactor; +} diff --git a/src/gui/entry/attachments/ImageAttachmentsWidget.h b/src/gui/entry/attachments/ImageAttachmentsWidget.h new file mode 100644 index 000000000..6c5ab95a3 --- /dev/null +++ b/src/gui/entry/attachments/ImageAttachmentsWidget.h @@ -0,0 +1,85 @@ +/* + * Copyright (C) 2025 KeePassXC Team + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 or (at your option) + * version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once + +#include "AttachmentTypes.h" + +#include +#include +#include + +namespace Ui +{ + class ImageAttachmentsWidget; +} + +class QGraphicsView; +class QGraphicsScene; + +class ZoomHelper : public QObject +{ + Q_OBJECT +public: + explicit ZoomHelper(double zoomFactor, double step, double min, double max, QObject* parent = nullptr); + + void zoomIn(); + void zoomOut(); + + void setZoomFactor(double zoomFactor); + double getZoomFactor() const; + + void setMinZoomOutFactor(double zoomFactor); + void setMaxZoomInFactor(double zoomFactor); + +signals: + void zoomChanged(double zoomFactor); + +private: + double m_zoomFactor; + double m_step; + + double m_minZoomOut; + double m_maxZoomIn; +}; + +class ImageAttachmentsWidget : public QWidget +{ + Q_OBJECT +public: + explicit ImageAttachmentsWidget(QWidget* parent = nullptr); + ~ImageAttachmentsWidget() override; + + void openAttachment(attachments::Attachment attachment, attachments::OpenMode mode); + attachments::Attachment getAttachment() const; + +private slots: + void onZoomChanged(const QString& zoomText); + void onWheelZoomEvent(QWheelEvent* event); + void onZoomFactorChanged(double zoomFactor); + +private: + void loadImage(); + + void initZoomComboBox(); + + QScopedPointer m_ui; + attachments::Attachment m_attachment; + + QPointer m_scene; + QPointer m_zoomHelper; +}; diff --git a/src/gui/entry/attachments/ImageAttachmentsWidget.ui b/src/gui/entry/attachments/ImageAttachmentsWidget.ui new file mode 100644 index 000000000..d95f6ea9a --- /dev/null +++ b/src/gui/entry/attachments/ImageAttachmentsWidget.ui @@ -0,0 +1,90 @@ + + + ImageAttachmentsWidget + + + + 0 + 0 + 400 + 300 + + + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + + Zoom: + + + + + + + + 0 + 0 + + + + true + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + Qt::Horizontal + + + + + + + + + + + ImageAttachmentsView + QGraphicsView +
    gui/entry/attachments/ImageAttachmentsView.h
    +
    +
    + + +
    diff --git a/src/gui/entry/attachments/TextAttachmentsEditWidget.cpp b/src/gui/entry/attachments/TextAttachmentsEditWidget.cpp new file mode 100644 index 000000000..1c0bcd223 --- /dev/null +++ b/src/gui/entry/attachments/TextAttachmentsEditWidget.cpp @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2025 KeePassXC Team + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 or (at your option) + * version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "TextAttachmentsEditWidget.h" +#include "ui_TextAttachmentsEditWidget.h" + +#include +#include +#include + +TextAttachmentsEditWidget::TextAttachmentsEditWidget(QWidget* parent) + : QWidget(parent) + , m_ui(new Ui::TextAttachmentsEditWidget()) +{ + m_ui->setupUi(this); + + connect(m_ui->attachmentsTextEdit, &QTextEdit::textChanged, this, &TextAttachmentsEditWidget::textChanged); + connect(m_ui->previewPushButton, &QPushButton::clicked, this, &TextAttachmentsEditWidget::previewButtonClicked); +} + +TextAttachmentsEditWidget::~TextAttachmentsEditWidget() = default; + +void TextAttachmentsEditWidget::openAttachment(attachments::Attachment attachments, attachments::OpenMode mode) +{ + m_attachment = std::move(attachments); + m_mode = mode; + + updateUi(); +} + +attachments::Attachment TextAttachmentsEditWidget::getAttachment() const +{ + return {m_attachment.name, m_ui->attachmentsTextEdit->toPlainText().toUtf8()}; +} + +void TextAttachmentsEditWidget::updateUi() +{ + m_ui->attachmentsTextEdit->setPlainText(m_attachment.data); + m_ui->attachmentsTextEdit->setReadOnly(m_mode == attachments::OpenMode::ReadOnly); +} diff --git a/src/gui/entry/attachments/TextAttachmentsEditWidget.h b/src/gui/entry/attachments/TextAttachmentsEditWidget.h new file mode 100644 index 000000000..0879d9251 --- /dev/null +++ b/src/gui/entry/attachments/TextAttachmentsEditWidget.h @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2025 KeePassXC Team + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 or (at your option) + * version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once + +#include "AttachmentTypes.h" + +#include +#include + +namespace Ui +{ + class TextAttachmentsEditWidget; +} + +class TextAttachmentsEditWidget : public QWidget +{ + Q_OBJECT +public: + explicit TextAttachmentsEditWidget(QWidget* parent = nullptr); + ~TextAttachmentsEditWidget() override; + + void openAttachment(attachments::Attachment attachment, attachments::OpenMode mode); + attachments::Attachment getAttachment() const; + +signals: + void textChanged(); + void previewButtonClicked(bool isChecked); + +private: + void updateUi(); + + QScopedPointer m_ui; + + attachments::Attachment m_attachment; + attachments::OpenMode m_mode; +}; diff --git a/src/gui/entry/attachments/TextAttachmentsEditWidget.ui b/src/gui/entry/attachments/TextAttachmentsEditWidget.ui new file mode 100644 index 000000000..e73894d15 --- /dev/null +++ b/src/gui/entry/attachments/TextAttachmentsEditWidget.ui @@ -0,0 +1,66 @@ + + + TextAttachmentsEditWidget + + + + 0 + 0 + 400 + 300 + + + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + + Preview + + + false + + + false + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + + + diff --git a/src/gui/entry/attachments/TextAttachmentsPreviewWidget.cpp b/src/gui/entry/attachments/TextAttachmentsPreviewWidget.cpp new file mode 100644 index 000000000..4775f289e --- /dev/null +++ b/src/gui/entry/attachments/TextAttachmentsPreviewWidget.cpp @@ -0,0 +1,133 @@ +/* + * Copyright (C) 2025 KeePassXC Team + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 or (at your option) + * version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "TextAttachmentsPreviewWidget.h" +#include "ui_TextAttachmentsPreviewWidget.h" + +#include + +#include +#include +#include +#include +#include + +namespace +{ + constexpr TextAttachmentsPreviewWidget::PreviewTextType ConvertToPreviewTextType(Tools::MimeType mimeType) noexcept + { + if (mimeType == Tools::MimeType::Html) { + return TextAttachmentsPreviewWidget::Html; + } + +#if (QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)) + if (mimeType == Tools::MimeType::Markdown) { + return TextAttachmentsPreviewWidget::Markdown; + } +#endif + + return TextAttachmentsPreviewWidget::PlainText; + } + +} // namespace + +TextAttachmentsPreviewWidget::TextAttachmentsPreviewWidget(QWidget* parent) + : QWidget(parent) + , m_ui(new Ui::TextAttachmentsPreviewWidget()) +{ + m_ui->setupUi(this); + + initTypeCombobox(); +} + +TextAttachmentsPreviewWidget::~TextAttachmentsPreviewWidget() = default; + +void TextAttachmentsPreviewWidget::openAttachment(attachments::Attachment attachments, attachments::OpenMode mode) +{ + if (mode == attachments::OpenMode::ReadWrite) { + qWarning() << "Read-write mode is not supported for text preview attachments"; + } + + m_attachment = std::move(attachments); + + updateUi(); +} + +attachments::Attachment TextAttachmentsPreviewWidget::getAttachment() const +{ + return m_attachment; +} + +void TextAttachmentsPreviewWidget::initTypeCombobox() +{ + QStandardItemModel* model = new QStandardItemModel(this); + + const auto metaEnum = QMetaEnum::fromType(); + for (int i = 0; i < metaEnum.keyCount(); ++i) { + QStandardItem* item = new QStandardItem(metaEnum.key(i)); + item->setData(metaEnum.value(i), Qt::UserRole); + model->appendRow(item); + } + + QSortFilterProxyModel* filterProxyMode = new QSortFilterProxyModel(this); + filterProxyMode->setSourceModel(model); + filterProxyMode->sort(0, Qt::SortOrder::DescendingOrder); + m_ui->typeComboBox->setModel(filterProxyMode); + + connect(m_ui->typeComboBox, + QOverload::of(&QComboBox::currentIndexChanged), + this, + &TextAttachmentsPreviewWidget::onTypeChanged); + + m_ui->typeComboBox->setCurrentIndex(m_ui->typeComboBox->findData(PlainText)); + + onTypeChanged(m_ui->typeComboBox->currentIndex()); +} + +void TextAttachmentsPreviewWidget::updateUi() +{ + if (!m_attachment.name.isEmpty()) { + const auto mimeType = Tools::getMimeType(QFileInfo(m_attachment.name)); + + auto index = m_ui->typeComboBox->findData(ConvertToPreviewTextType(mimeType)); + m_ui->typeComboBox->setCurrentIndex(index); + } + + onTypeChanged(m_ui->typeComboBox->currentIndex()); +} + +void TextAttachmentsPreviewWidget::onTypeChanged(int index) +{ + if (index < 0) { + qWarning() << "TextAttachmentsPreviewWidget: Unknown text format"; + } + + const auto fileType = m_ui->typeComboBox->itemData(index).toInt(); + if (fileType == TextAttachmentsPreviewWidget::PreviewTextType::PlainText) { + m_ui->previewTextBrowser->setPlainText(m_attachment.data); + } + + if (fileType == TextAttachmentsPreviewWidget::PreviewTextType::Html) { + m_ui->previewTextBrowser->setHtml(m_attachment.data); + } + +#if (QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)) + if (fileType == TextAttachmentsPreviewWidget::PreviewTextType::Markdown) { + m_ui->previewTextBrowser->setMarkdown(m_attachment.data); + } +#endif +} diff --git a/src/gui/entry/attachments/TextAttachmentsPreviewWidget.h b/src/gui/entry/attachments/TextAttachmentsPreviewWidget.h new file mode 100644 index 000000000..c7d20eb9d --- /dev/null +++ b/src/gui/entry/attachments/TextAttachmentsPreviewWidget.h @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2025 KeePassXC Team + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 or (at your option) + * version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once + +#include "AttachmentTypes.h" + +#include +#include + +namespace Ui +{ + class TextAttachmentsPreviewWidget; +} + +class TextAttachmentsPreviewWidget : public QWidget +{ + Q_OBJECT +public: + explicit TextAttachmentsPreviewWidget(QWidget* parent = nullptr); + ~TextAttachmentsPreviewWidget() override; + + void openAttachment(attachments::Attachment attachment, attachments::OpenMode mode); + attachments::Attachment getAttachment() const; + + enum PreviewTextType : int + { + Html, + PlainText, +#if (QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)) + Markdown +#endif + }; + + Q_ENUM(PreviewTextType) + +private slots: + void onTypeChanged(int index); + +private: + void initTypeCombobox(); + void updateUi(); + + QScopedPointer m_ui; + + attachments::Attachment m_attachment; +}; diff --git a/src/gui/entry/attachments/TextAttachmentsPreviewWidget.ui b/src/gui/entry/attachments/TextAttachmentsPreviewWidget.ui new file mode 100644 index 000000000..2ee97aa22 --- /dev/null +++ b/src/gui/entry/attachments/TextAttachmentsPreviewWidget.ui @@ -0,0 +1,70 @@ + + + TextAttachmentsPreviewWidget + + + + 0 + 0 + 400 + 300 + + + + Form + + + + 6 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + + Type: + + + + + + + false + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + + + diff --git a/src/gui/entry/attachments/TextAttachmentsWidget.cpp b/src/gui/entry/attachments/TextAttachmentsWidget.cpp new file mode 100644 index 000000000..d0935c6af --- /dev/null +++ b/src/gui/entry/attachments/TextAttachmentsWidget.cpp @@ -0,0 +1,105 @@ +/* + * Copyright (C) 2025 KeePassXC Team + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 or (at your option) + * version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "TextAttachmentsWidget.h" +#include "TextAttachmentsEditWidget.h" +#include "TextAttachmentsPreviewWidget.h" + +#include "ui_TextAttachmentsWidget.h" + +#include +#include +#include + +TextAttachmentsWidget::TextAttachmentsWidget(QWidget* parent) + : QWidget(parent) + , m_ui(new Ui::TextAttachmentsWidget()) + , m_previewUpdateTimer(new QTimer(this)) + , m_mode(attachments::OpenMode::ReadOnly) +{ + m_ui->setupUi(this); + initWidget(); +} + +TextAttachmentsWidget::~TextAttachmentsWidget() = default; + +void TextAttachmentsWidget::openAttachment(attachments::Attachment attachment, attachments::OpenMode mode) +{ + m_attachment = std::move(attachment); + m_mode = mode; + + updateWidget(); +} + +attachments::Attachment TextAttachmentsWidget::getAttachment() const +{ + if (m_mode == attachments::OpenMode::ReadWrite) { + return m_editWidget->getAttachment(); + } + + return m_attachment; +} + +void TextAttachmentsWidget::updateWidget() +{ + if (m_mode == attachments::OpenMode::ReadOnly) { + m_splitter->setSizes({0, 1}); + m_editWidget->hide(); + } else { + m_splitter->setSizes({1, 0}); + m_editWidget->show(); + } + + m_editWidget->openAttachment(m_attachment, m_mode); + m_previewWidget->openAttachment(m_attachment, attachments::OpenMode::ReadOnly); +} + +void TextAttachmentsWidget::initWidget() +{ + m_splitter = new QSplitter(this); + m_editWidget = new TextAttachmentsEditWidget(this); + m_previewWidget = new TextAttachmentsPreviewWidget(this); + + m_previewUpdateTimer->setSingleShot(true); + m_previewUpdateTimer->setInterval(500); + + // Only update the preview after a set timeout and if it is visible + connect(m_previewUpdateTimer, &QTimer::timeout, this, [this] { + if (m_previewWidget->width() > 0) { + m_attachment = m_editWidget->getAttachment(); + m_previewWidget->openAttachment(m_attachment, attachments::OpenMode::ReadOnly); + } + }); + + connect( + m_editWidget, &TextAttachmentsEditWidget::textChanged, m_previewUpdateTimer, QOverload<>::of(&QTimer::start)); + + connect(m_editWidget, &TextAttachmentsEditWidget::previewButtonClicked, [this] { + const auto sizes = m_splitter->sizes(); + const auto previewSize = sizes.value(1, 0) > 0 ? 0 : 1; + m_splitter->setSizes({1, previewSize}); + }); + + m_splitter->addWidget(m_editWidget); + m_splitter->addWidget(m_previewWidget); + // Prevent collapsing of the edit widget + m_splitter->setCollapsible(0, false); + + m_ui->verticalLayout->addWidget(m_splitter); + + updateWidget(); +} diff --git a/src/gui/entry/attachments/TextAttachmentsWidget.h b/src/gui/entry/attachments/TextAttachmentsWidget.h new file mode 100644 index 000000000..f4709823f --- /dev/null +++ b/src/gui/entry/attachments/TextAttachmentsWidget.h @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2025 KeePassXC Team + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 or (at your option) + * version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once + +#include "AttachmentTypes.h" + +#include +#include +#include + +namespace Ui +{ + class TextAttachmentsWidget; +} + +class QSplitter; +class QTimer; +class TextAttachmentsPreviewWidget; +class TextAttachmentsEditWidget; + +class TextAttachmentsWidget : public QWidget +{ + Q_OBJECT +public: + explicit TextAttachmentsWidget(QWidget* parent = nullptr); + ~TextAttachmentsWidget() override; + + void openAttachment(attachments::Attachment attachment, attachments::OpenMode mode); + attachments::Attachment getAttachment() const; + +private: + void updateWidget(); + void initWidget(); + + QScopedPointer m_ui; + QPointer m_splitter; + QPointer m_editWidget; + QPointer m_previewWidget; + QPointer m_previewUpdateTimer; + + attachments::Attachment m_attachment; + attachments::OpenMode m_mode; +}; diff --git a/src/gui/entry/attachments/TextAttachmentsWidget.ui b/src/gui/entry/attachments/TextAttachmentsWidget.ui new file mode 100644 index 000000000..9c18a7c60 --- /dev/null +++ b/src/gui/entry/attachments/TextAttachmentsWidget.ui @@ -0,0 +1,36 @@ + + + TextAttachmentsWidget + + + + 0 + 0 + 732 + 432 + + + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + diff --git a/src/gui/export/ExportDialog.cpp b/src/gui/export/ExportDialog.cpp index 3537505cc..4c2c2e6b5 100644 --- a/src/gui/export/ExportDialog.cpp +++ b/src/gui/export/ExportDialog.cpp @@ -19,7 +19,7 @@ #include "ui_ExportDialog.h" #include "gui/FileDialog.h" -#include "gui/HtmlExporter.h" +#include "gui/HtmlGuiExporter.h" ExportDialog::ExportDialog(QSharedPointer db, DatabaseTabWidget* parent) : QDialog(parent) @@ -44,9 +44,7 @@ ExportDialog::ExportDialog(QSharedPointer db, DatabaseTabWidget* MessageWidget::Warning); } -ExportDialog::~ExportDialog() -{ -} +ExportDialog::~ExportDialog() = default; QString ExportDialog::getStrategyName(ExportSortingStrategy strategy) { @@ -74,7 +72,7 @@ void ExportDialog::exportDatabase() FileDialog::saveLastDir("html", fileName, true); - HtmlExporter htmlExporter; + HtmlGuiExporter htmlExporter; if (!htmlExporter.exportDatabase( fileName, m_db, sortBy != ExportSortingStrategy::BY_DATABASE_ORDER, ascendingOrder)) { emit exportFailed(htmlExporter.errorString()); diff --git a/src/gui/group/EditGroupWidget.cpp b/src/gui/group/EditGroupWidget.cpp index 39f5bc445..bf38caf2e 100644 --- a/src/gui/group/EditGroupWidget.cpp +++ b/src/gui/group/EditGroupWidget.cpp @@ -112,9 +112,7 @@ EditGroupWidget::EditGroupWidget(QWidget* parent) setupModifiedTracking(); } -EditGroupWidget::~EditGroupWidget() -{ -} +EditGroupWidget::~EditGroupWidget() = default; void EditGroupWidget::setupModifiedTracking() { @@ -198,6 +196,7 @@ void EditGroupWidget::loadGroup(Group* group, bool create, const QSharedPointer< auto inheritOnlyHttp = false; auto inheritNoHttp = false; auto inheritOmitWww = false; + auto inheritRestrictKey = QString(); auto parent = group->parentGroup(); if (parent) { @@ -206,6 +205,7 @@ void EditGroupWidget::loadGroup(Group* group, bool create, const QSharedPointer< inheritOnlyHttp = parent->resolveCustomDataTriState(BrowserService::OPTION_ONLY_HTTP_AUTH); inheritNoHttp = parent->resolveCustomDataTriState(BrowserService::OPTION_NOT_HTTP_AUTH); inheritOmitWww = parent->resolveCustomDataTriState(BrowserService::OPTION_OMIT_WWW); + inheritRestrictKey = parent->resolveCustomDataString(BrowserService::OPTION_RESTRICT_KEY); } // If the page has not been created at all, some of the elements are null @@ -221,6 +221,7 @@ void EditGroupWidget::loadGroup(Group* group, bool create, const QSharedPointer< addTriStateItems(m_browserUi->browserIntegrationOnlyHttpAuthComboBox, inheritOnlyHttp); addTriStateItems(m_browserUi->browserIntegrationNotHttpAuthComboBox, inheritNoHttp); addTriStateItems(m_browserUi->browserIntegrationOmitWwwCombobox, inheritOmitWww); + addRestrictKeyComboBoxItems(m_db->metadata()->customData()->keys(), inheritRestrictKey); m_browserUi->browserIntegrationHideEntriesComboBox->setCurrentIndex( indexFromTriState(group->resolveCustomDataTriState(BrowserService::OPTION_HIDE_ENTRY, false))); @@ -232,6 +233,7 @@ void EditGroupWidget::loadGroup(Group* group, bool create, const QSharedPointer< indexFromTriState(group->resolveCustomDataTriState(BrowserService::OPTION_NOT_HTTP_AUTH, false))); m_browserUi->browserIntegrationOmitWwwCombobox->setCurrentIndex( indexFromTriState(group->resolveCustomDataTriState(BrowserService::OPTION_OMIT_WWW, false))); + setRestrictKeyComboBoxIndex(group); } else if (hasPage(m_browserWidget)) { setPageHidden(m_browserWidget, true); } @@ -305,6 +307,7 @@ void EditGroupWidget::apply() m_temporaryGroup->setCustomDataTriState( BrowserService::OPTION_OMIT_WWW, triStateFromIndex(m_browserUi->browserIntegrationOmitWwwCombobox->currentIndex())); + setRestrictKeyCustomData(m_temporaryGroup->customData()); } #endif @@ -446,3 +449,58 @@ Group::TriState EditGroupWidget::triStateFromIndex(int index) return Group::Inherit; } } + +#ifdef WITH_XC_BROWSER +void EditGroupWidget::addRestrictKeyComboBoxItems(QStringList const& keyList, QString inheritValue) +{ + auto comboBox = m_browserUi->browserIntegrationRestrictKeyCombobox; + + comboBox->clear(); + comboBox->addItem( + tr("Inherit from parent group (%1)").arg(BrowserService::decodeCustomDataRestrictKey(inheritValue))); + comboBox->addItem(tr("Disable")); + + comboBox->insertSeparator(2); + + // Add all the browser keys to the combobox + for (const QString& key : keyList) { + if (key.startsWith(CustomData::BrowserKeyPrefix)) { + auto strippedKey = key; + strippedKey.remove(CustomData::BrowserKeyPrefix); + comboBox->addItem(strippedKey); + } + } +} + +void EditGroupWidget::setRestrictKeyComboBoxIndex(const Group* group) +{ + auto comboBox = m_browserUi->browserIntegrationRestrictKeyCombobox; + + if (!group || !group->customData()->contains(BrowserService::OPTION_RESTRICT_KEY)) { + comboBox->setCurrentIndex(0); + return; + } + + auto key = group->customData()->value(BrowserService::OPTION_RESTRICT_KEY); + if (key.isEmpty()) { + comboBox->setCurrentIndex(1); + } else { + comboBox->setCurrentText(key); + } +} + +// Set the customData regarding OPTION_RESTRICT_KEY +void EditGroupWidget::setRestrictKeyCustomData(CustomData* customData) +{ + auto comboBox = m_browserUi->browserIntegrationRestrictKeyCombobox; + auto key = BrowserService::OPTION_RESTRICT_KEY; + auto idx = comboBox->currentIndex(); + if (idx == 0) { + customData->remove(key); + } else if (idx == 1) { + customData->set(key, QString()); + } else { + customData->set(key, comboBox->currentText()); + } +} +#endif diff --git a/src/gui/group/EditGroupWidget.h b/src/gui/group/EditGroupWidget.h index 1481d2500..35a84d768 100644 --- a/src/gui/group/EditGroupWidget.h +++ b/src/gui/group/EditGroupWidget.h @@ -39,9 +39,7 @@ namespace Ui class IEditGroupPage { public: - virtual ~IEditGroupPage() - { - } + virtual ~IEditGroupPage() = default; virtual QString name() = 0; virtual QIcon icon() = 0; virtual QWidget* createWidget() = 0; @@ -55,7 +53,7 @@ class EditGroupWidget : public EditWidget public: explicit EditGroupWidget(QWidget* parent = nullptr); - ~EditGroupWidget(); + ~EditGroupWidget() override; void loadGroup(Group* group, bool create, const QSharedPointer& database); void clear(); @@ -83,6 +81,10 @@ private: Group::TriState triStateFromIndex(int index); void setupModifiedTracking(); + void addRestrictKeyComboBoxItems(QStringList const& keyList, QString inheritValue); + void setRestrictKeyComboBoxIndex(const Group* group); + void setRestrictKeyCustomData(CustomData* customData); + const QScopedPointer m_mainUi; QPointer m_editGroupWidgetMain; diff --git a/src/gui/group/EditGroupWidgetBrowser.ui b/src/gui/group/EditGroupWidgetBrowser.ui index dfe4b5971..8d94693fd 100644 --- a/src/gui/group/EditGroupWidgetBrowser.ui +++ b/src/gui/group/EditGroupWidgetBrowser.ui @@ -136,6 +136,23 @@
    + + + Restrict matching to given browser key: + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + Restrict matching to given browser key toggle for this and sub groups + + + + Qt::Vertical @@ -158,6 +175,7 @@ browserIntegrationOnlyHttpAuthComboBox browserIntegrationNotHttpAuthComboBox browserIntegrationOmitWwwCombobox + browserIntegrationRestrictKeyCombobox diff --git a/src/gui/group/GroupModel.cpp b/src/gui/group/GroupModel.cpp index 57ea56235..18b926dc2 100644 --- a/src/gui/group/GroupModel.cpp +++ b/src/gui/group/GroupModel.cpp @@ -74,7 +74,7 @@ int GroupModel::columnCount(const QModelIndex& parent) const QModelIndex GroupModel::index(int row, int column, const QModelIndex& parent) const { if (!hasIndex(row, column, parent)) { - return QModelIndex(); + return {}; } Group* group; @@ -91,7 +91,7 @@ QModelIndex GroupModel::index(int row, int column, const QModelIndex& parent) co QModelIndex GroupModel::parent(const QModelIndex& index) const { if (!index.isValid()) { - return QModelIndex(); + return {}; } return parent(groupFromIndex(index)); @@ -103,7 +103,7 @@ QModelIndex GroupModel::parent(Group* group) const if (!parentGroup) { // index is already the root group - return QModelIndex(); + return {}; } else { const Group* grandParentGroup = parentGroup->parentGroup(); if (!grandParentGroup) { @@ -118,7 +118,7 @@ QModelIndex GroupModel::parent(Group* group) const QVariant GroupModel::data(const QModelIndex& index, int role) const { if (!index.isValid()) { - return QVariant(); + return {}; } Group* group = groupFromIndex(index); @@ -145,7 +145,7 @@ QVariant GroupModel::data(const QModelIndex& index, int role) const } return tooltip; } else { - return QVariant(); + return {}; } } @@ -155,7 +155,7 @@ QVariant GroupModel::headerData(int section, Qt::Orientation orientation, int ro Q_UNUSED(orientation); Q_UNUSED(role); - return QVariant(); + return {}; } QModelIndex GroupModel::index(Group* group) const @@ -333,7 +333,7 @@ QMimeData* GroupModel::mimeData(const QModelIndexList& indexes) const return nullptr; } - QMimeData* data = new QMimeData(); + auto data = new QMimeData(); QByteArray encoded; QDataStream stream(&encoded, QIODevice::WriteOnly); diff --git a/src/gui/group/GroupView.cpp b/src/gui/group/GroupView.cpp index 1fc4700b0..46cc0af6a 100644 --- a/src/gui/group/GroupView.cpp +++ b/src/gui/group/GroupView.cpp @@ -33,6 +33,7 @@ GroupView::GroupView(Database* db, QWidget* parent) QTreeView::setModel(m_model); setHeaderHidden(true); setUniformRowHeights(true); + setTextElideMode(Qt::ElideNone); // clang-format off connect(this, SIGNAL(expanded(QModelIndex)), SLOT(expandedChanged(QModelIndex))); @@ -92,6 +93,7 @@ void GroupView::contextMenuShortcutPressed() void GroupView::changeDatabase(const QSharedPointer& newDb) { m_model->changeDatabase(newDb.data()); + setColumnWidth(0, sizeHintForColumn(0)); } void GroupView::dragMoveEvent(QDragMoveEvent* event) @@ -134,6 +136,7 @@ void GroupView::expandedChanged(const QModelIndex& index) Group* group = m_model->groupFromIndex(index); group->setExpanded(isExpanded(index)); + setColumnWidth(0, sizeHintForColumn(0)); } void GroupView::recInitExpanded(Group* group) diff --git a/src/gui/osutils/DeviceListener.cpp b/src/gui/osutils/DeviceListener.cpp index 9946295e9..d48039308 100644 --- a/src/gui/osutils/DeviceListener.cpp +++ b/src/gui/osutils/DeviceListener.cpp @@ -35,7 +35,7 @@ void DeviceListener::connectSignals(DEVICELISTENER_IMPL* listener) { connect(listener, &DEVICELISTENER_IMPL::devicePlugged, this, [&](bool state, void* ctx, void* device) { // Wait a few ms to prevent USB device access conflicts - QTimer::singleShot(50, [&] { emit devicePlugged(state, ctx, device); }); + QTimer::singleShot(50, this, [&] { emit devicePlugged(state, ctx, device); }); }); } @@ -57,7 +57,7 @@ DeviceListener::registerHotplugCallback(bool arrived, bool left, int vendorId, i void DeviceListener::deregisterHotplugCallback(Handle handle) { #if defined(Q_OS_UNIX) && !defined(Q_OS_MACOS) - m_listeners[0]->deregisterHotplugCallback(static_cast(handle)); + m_listeners[0]->deregisterHotplugCallback(handle); #else if (m_listeners.contains(handle)) { m_listeners[handle]->deregisterHotplugCallback(); diff --git a/src/gui/osutils/OSUtilsBase.cpp b/src/gui/osutils/OSUtilsBase.cpp index 63ce71247..8a95b7f55 100644 --- a/src/gui/osutils/OSUtilsBase.cpp +++ b/src/gui/osutils/OSUtilsBase.cpp @@ -22,9 +22,7 @@ OSUtilsBase::OSUtilsBase(QObject* parent) { } -OSUtilsBase::~OSUtilsBase() -{ -} +OSUtilsBase::~OSUtilsBase() = default; bool OSUtilsBase::setPreventScreenCapture(QWindow*, bool) const { diff --git a/src/gui/osutils/OSUtilsBase.h b/src/gui/osutils/OSUtilsBase.h index 080a53413..11d739fde 100644 --- a/src/gui/osutils/OSUtilsBase.h +++ b/src/gui/osutils/OSUtilsBase.h @@ -56,6 +56,11 @@ public: */ virtual bool isCapslockEnabled() = 0; + /** + * @param enable Toggle protection on user input (if available). + */ + virtual void setUserInputProtection(bool enable) = 0; + virtual void registerNativeEventFilter() = 0; virtual bool registerGlobalShortcut(const QString& name, @@ -82,7 +87,7 @@ signals: protected: explicit OSUtilsBase(QObject* parent = nullptr); - virtual ~OSUtilsBase(); + ~OSUtilsBase() override; }; #endif // KEEPASSXC_OSUTILSBASE_H diff --git a/src/gui/osutils/ScreenLockListener.cpp b/src/gui/osutils/ScreenLockListener.cpp index 2c1ba055a..1e3e4e47c 100644 --- a/src/gui/osutils/ScreenLockListener.cpp +++ b/src/gui/osutils/ScreenLockListener.cpp @@ -25,6 +25,4 @@ ScreenLockListener::ScreenLockListener(QWidget* parent) connect(m_listener, SIGNAL(screenLocked()), this, SIGNAL(screenLocked())); } -ScreenLockListener::~ScreenLockListener() -{ -} +ScreenLockListener::~ScreenLockListener() = default; diff --git a/src/gui/osutils/macutils/AppKit.h b/src/gui/osutils/macutils/AppKit.h index 309c05b90..260b6c208 100644 --- a/src/gui/osutils/macutils/AppKit.h +++ b/src/gui/osutils/macutils/AppKit.h @@ -1,6 +1,6 @@ /* + * Copyright (C) 2023 KeePassXC Team * Copyright (C) 2016 Lennart Glauer - * Copyright (C) 2017 KeePassXC Team * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -19,8 +19,8 @@ #ifndef KEEPASSX_APPKIT_H #define KEEPASSX_APPKIT_H -#include #include +#include #include class QWindow; @@ -47,7 +47,7 @@ public: void setWindowSecurity(QWindow* window, bool state); signals: - void lockDatabases(); + void userSwitched(); void interfaceThemeChanged(); private: diff --git a/src/gui/osutils/macutils/AppKitImpl.mm b/src/gui/osutils/macutils/AppKitImpl.mm index 439cf18d4..a2b30e553 100644 --- a/src/gui/osutils/macutils/AppKitImpl.mm +++ b/src/gui/osutils/macutils/AppKitImpl.mm @@ -19,6 +19,9 @@ #import "AppKitImpl.h" #import #import +#if __clang_major__ >= 13 && MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_VERSION_12_3 +#import +#endif @implementation AppKitImpl @@ -32,7 +35,7 @@ selector:@selector(didDeactivateApplicationObserver:) name:NSWorkspaceDidDeactivateApplicationNotification object:nil]; - + [[[NSWorkspace sharedWorkspace] notificationCenter] addObserver:self selector:@selector(userSwitchHandler:) name:NSWorkspaceSessionDidResignActiveNotification @@ -160,7 +163,7 @@ { if ([[notification name] isEqualToString:NSWorkspaceSessionDidResignActiveNotification] && m_appkit) { - emit m_appkit->lockDatabases(); + emit m_appkit->userSwitched(); } } @@ -181,28 +184,37 @@ // // Check if screen recording is enabled, may show an popup asking for permissions // -- (bool) enableScreenRecording +- (bool) enableScreenRecording { -#if __clang_major__ >= 9 && MAC_OS_X_VERSION_MIN_REQUIRED >= 1080 - if (@available(macOS 10.15, *)) { - // Request screen recording permission on macOS 10.15+ - // This is necessary to get the current window title - CGDisplayStreamRef stream = CGDisplayStreamCreate(CGMainDisplayID(), 1, 1, kCVPixelFormatType_32BGRA, nil, - ^(CGDisplayStreamFrameStatus status, uint64_t displayTime, - IOSurfaceRef frameSurface, CGDisplayStreamUpdateRef updateRef) { - Q_UNUSED(status); - Q_UNUSED(displayTime); - Q_UNUSED(frameSurface); - Q_UNUSED(updateRef); - }); - if (stream) { - CFRelease(stream); - } else { - return NO; - } +#if __clang_major__ >= 13 && MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_VERSION_12_3 + if (@available(macOS 12.3, *)) { + __block BOOL hasPermission = NO; + dispatch_semaphore_t sema = dispatch_semaphore_create(0); + + // Attempt to use SCShareableContent to check for screen recording permission + [SCShareableContent getShareableContentWithCompletionHandler:^(SCShareableContent * _Nullable content, + NSError * _Nullable error) { + Q_UNUSED(error); + if (content) { + // Successfully obtained content, indicating permission is granted + hasPermission = YES; + } else { + // No permission or other error occurred + hasPermission = NO; + } + // Notify the semaphore that the asynchronous task is complete + dispatch_semaphore_signal(sema); + }]; + + // Wait for the asynchronous callback to complete + dispatch_time_t timeout = dispatch_time(DISPATCH_TIME_NOW, 5 * NSEC_PER_SEC); + dispatch_semaphore_wait(sema, timeout); + + // Return the final result + return hasPermission; } #endif - return YES; + return YES; // Return YES for macOS versions that do not support ScreenCaptureKit } - (void) toggleForegroundApp:(bool) foreground diff --git a/src/core/MacPasteboard.cpp b/src/gui/osutils/macutils/MacPasteboard.cpp similarity index 100% rename from src/core/MacPasteboard.cpp rename to src/gui/osutils/macutils/MacPasteboard.cpp diff --git a/src/core/MacPasteboard.h b/src/gui/osutils/macutils/MacPasteboard.h similarity index 100% rename from src/core/MacPasteboard.h rename to src/gui/osutils/macutils/MacPasteboard.h diff --git a/src/gui/osutils/macutils/MacUtils.cpp b/src/gui/osutils/macutils/MacUtils.cpp index 0f2cc6161..b943561dc 100644 --- a/src/gui/osutils/macutils/MacUtils.cpp +++ b/src/gui/osutils/macutils/MacUtils.cpp @@ -1,6 +1,6 @@ /* + * Copyright (C) 2023 KeePassXC Team * Copyright (C) 2012 Felix Geyer - * Copyright (C) 2018 KeePassXC Team * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -39,7 +39,7 @@ MacUtils::MacUtils(QObject* parent) : OSUtilsBase(parent) , m_appkit(new AppKit()) { - connect(m_appkit.data(), SIGNAL(lockDatabases()), SIGNAL(lockDatabases())); + connect(m_appkit.data(), SIGNAL(userSwitched()), SIGNAL(userSwitched())); connect(m_appkit.data(), SIGNAL(interfaceThemeChanged()), SIGNAL(interfaceThemeChanged())); connect(m_appkit.data(), &AppKit::interfaceThemeChanged, this, [this]() { // Emit with delay, since isStatusBarDark() still returns the old value @@ -130,6 +130,8 @@ void MacUtils::setLaunchAtStartup(bool enable) if (enable) { QSettings agent(getLaunchAgentFilename(), QSettings::NativeFormat); agent.setValue("Label", qApp->property("KPXC_QUALIFIED_APPNAME").toString()); + agent.setValue("AssociatedBundleIdentifiers", qApp->property("KPXC_QUALIFIED_APPNAME").toString()); + agent.setValue("Program", QApplication::applicationFilePath()); agent.setValue("ProgramArguments", QStringList() << QApplication::applicationFilePath()); agent.setValue("RunAtLoad", true); agent.setValue("StandardErrorPath", "/dev/null"); @@ -148,6 +150,26 @@ bool MacUtils::isCapslockEnabled() #endif } +void MacUtils::setUserInputProtection(bool enable) +{ + static bool secureInputEnabled = false; + if (enable) { + /* + * MacOS keeps a single counter over all apps that needs to be zero to disable secure input. By never going + * higher than 1 internally this makes sure secure input doesn't stay active after calling this function + * multiple times. + */ + if (secureInputEnabled) { + DisableSecureEventInput(); + } + EnableSecureEventInput(); + } else { + DisableSecureEventInput(); + } + // Store our last known state + secureInputEnabled = enable; +} + /** * Toggle application state between foreground app and UIElement app. * Foreground apps have dock icons, UIElement apps do not. diff --git a/src/gui/osutils/macutils/MacUtils.h b/src/gui/osutils/macutils/MacUtils.h index 1281aa072..5e0e121d5 100644 --- a/src/gui/osutils/macutils/MacUtils.h +++ b/src/gui/osutils/macutils/MacUtils.h @@ -1,6 +1,6 @@ /* + * Copyright (C) 2023 KeePassXC Team * Copyright (C) 2012 Felix Geyer - * Copyright (C) 2017 KeePassXC Team * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -40,6 +40,7 @@ public: bool isLaunchAtStartupEnabled() const override; void setLaunchAtStartup(bool enable) override; bool isCapslockEnabled() override; + void setUserInputProtection(bool enable) override; WId activeWindow(); bool raiseWindow(WId pid); @@ -66,7 +67,7 @@ public: bool setPreventScreenCapture(QWindow* window, bool prevent) const override; signals: - void lockDatabases(); + void userSwitched(); protected: explicit MacUtils(QObject* parent = nullptr); diff --git a/src/gui/osutils/nixutils/DeviceListenerLibUsb.cpp b/src/gui/osutils/nixutils/DeviceListenerLibUsb.cpp index 6cbb4a33e..97233fbb0 100644 --- a/src/gui/osutils/nixutils/DeviceListenerLibUsb.cpp +++ b/src/gui/osutils/nixutils/DeviceListenerLibUsb.cpp @@ -20,6 +20,7 @@ #include #include +#include #include DeviceListenerLibUsb::DeviceListenerLibUsb(QWidget* parent) @@ -49,7 +50,8 @@ namespace } } // namespace -int DeviceListenerLibUsb::registerHotplugCallback(bool arrived, bool left, int vendorId, int productId, const QUuid*) +DeviceListenerLibUsb::Handle +DeviceListenerLibUsb::registerHotplugCallback(bool arrived, bool left, int vendorId, int productId, const QUuid*) { if (!m_ctx) { if (libusb_init(reinterpret_cast(&m_ctx)) != LIBUSB_SUCCESS) { @@ -66,7 +68,8 @@ int DeviceListenerLibUsb::registerHotplugCallback(bool arrived, bool left, int v events |= LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT; } - int handle = 0; + Handle handle = 0; + auto* handleNative = reinterpret_cast(&handle); const QPointer that = this; const int ret = libusb_hotplug_register_callback( static_cast(m_ctx), @@ -77,14 +80,14 @@ int DeviceListenerLibUsb::registerHotplugCallback(bool arrived, bool left, int v LIBUSB_HOTPLUG_MATCH_ANY, [](libusb_context* ctx, libusb_device* device, libusb_hotplug_event event, void* userData) -> int { if (!ctx) { - return 0; + return true; } emit static_cast(userData)->devicePlugged( event == LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED, ctx, device); - return 0; + return false; }, that, - &handle); + handleNative); if (ret != LIBUSB_SUCCESS) { qWarning("Failed to register USB listener callback."); handle = 0; @@ -94,20 +97,27 @@ int DeviceListenerLibUsb::registerHotplugCallback(bool arrived, bool left, int v // Avoid race conditions m_usbEvents.waitForFinished(); } - if (!m_usbEvents.isRunning()) { - m_completed = false; - m_usbEvents = QtConcurrent::run(handleUsbEvents, static_cast(m_ctx), &m_completed); + if (handle > 0) { + m_callbackHandles.insert(handle); + if (!m_usbEvents.isRunning()) { + m_completed = false; + m_usbEvents = QtConcurrent::run(handleUsbEvents, static_cast(m_ctx), &m_completed); + } } - m_callbackHandles.insert(handle); return handle; } -void DeviceListenerLibUsb::deregisterHotplugCallback(int handle) +void DeviceListenerLibUsb::deregisterHotplugCallback(Handle handle) { if (!m_ctx || !m_callbackHandles.contains(handle)) { return; } - libusb_hotplug_deregister_callback(static_cast(m_ctx), handle); +#ifdef Q_OS_FREEBSD + auto* handleNative = reinterpret_cast(handle); +#else + auto handleNative = static_cast(handle); +#endif + libusb_hotplug_deregister_callback(static_cast(m_ctx), handleNative); m_callbackHandles.remove(handle); if (m_callbackHandles.isEmpty() && m_usbEvents.isRunning()) { diff --git a/src/gui/osutils/nixutils/DeviceListenerLibUsb.h b/src/gui/osutils/nixutils/DeviceListenerLibUsb.h index 13257e21c..4d207c847 100644 --- a/src/gui/osutils/nixutils/DeviceListenerLibUsb.h +++ b/src/gui/osutils/nixutils/DeviceListenerLibUsb.h @@ -32,12 +32,14 @@ class DeviceListenerLibUsb : public QObject Q_OBJECT public: + typedef qintptr Handle; explicit DeviceListenerLibUsb(QWidget* parent); DeviceListenerLibUsb(const DeviceListenerLibUsb&) = delete; ~DeviceListenerLibUsb() override; - int registerHotplugCallback(bool arrived, bool left, int vendorId = -1, int productId = -1, const QUuid* = nullptr); - void deregisterHotplugCallback(int handle); + Handle + registerHotplugCallback(bool arrived, bool left, int vendorId = -1, int productId = -1, const QUuid* = nullptr); + void deregisterHotplugCallback(Handle handle); void deregisterAllHotplugCallbacks(); signals: @@ -45,7 +47,7 @@ signals: private: void* m_ctx; - QSet m_callbackHandles; + QSet m_callbackHandles; QFuture m_usbEvents; QAtomicInt m_completed; }; diff --git a/src/gui/osutils/nixutils/NixUtils.cpp b/src/gui/osutils/nixutils/NixUtils.cpp index a5c18d8d8..30b7e21e4 100644 --- a/src/gui/osutils/nixutils/NixUtils.cpp +++ b/src/gui/osutils/nixutils/NixUtils.cpp @@ -18,19 +18,18 @@ #include "NixUtils.h" #include "config-keepassx.h" +#include "core/Config.h" +#include "core/Global.h" #include #include #include #include #include +#include #include #include #include -#ifdef KEEPASSXC_DIST_FLATPAK -#include "core/Config.h" -#include -#endif #ifdef WITH_XC_X11 #include @@ -88,9 +87,7 @@ NixUtils::NixUtils(QObject* parent) sessionBus.callWithCallback(msg, this, SLOT(handleColorSchemeRead(QDBusVariant))); } -NixUtils::~NixUtils() -{ -} +NixUtils::~NixUtils() = default; bool NixUtils::isDarkMode() const { @@ -129,9 +126,8 @@ QString NixUtils::getAutostartDesktopFilename(bool createDirs) const bool NixUtils::isLaunchAtStartupEnabled() const { -#if !defined(KEEPASSXC_DIST_FLATPAK) +#ifndef KEEPASSXC_DIST_FLATPAK return QFile::exists(getAutostartDesktopFilename()); - ; #else return config()->get(Config::GUI_LaunchAtStartup).toBool(); #endif @@ -139,7 +135,7 @@ bool NixUtils::isLaunchAtStartupEnabled() const void NixUtils::setLaunchAtStartup(bool enable) { -#if !defined(KEEPASSXC_DIST_FLATPAK) +#ifndef KEEPASSXC_DIST_FLATPAK if (enable) { QFile desktopFile(getAutostartDesktopFilename(true)); if (!desktopFile.open(QIODevice::WriteOnly)) { @@ -169,7 +165,7 @@ void NixUtils::setLaunchAtStartup(bool enable) << QStringLiteral("X-GNOME-Autostart-enabled=true") << '\n' << QStringLiteral("X-GNOME-Autostart-Delay=2") << '\n' << QStringLiteral("X-KDE-autostart-after=panel") << '\n' - << QStringLiteral("X-LXQt-Need-Tray=true") << endl; + << QStringLiteral("X-LXQt-Need-Tray=true") << Qt::endl; desktopFile.close(); } else if (isLaunchAtStartupEnabled()) { QFile::remove(getAutostartDesktopFilename()); @@ -201,7 +197,7 @@ void NixUtils::setLaunchAtStartup(bool enable) SLOT(launchAtStartupRequested(uint, QVariantMap))); if (!res) { - qDebug() << "Could not connect to org.freedesktop.portal.Request::Response signal"; + qDebug() << "DBus Error: could not connect to org.freedesktop.portal.Request"; } #endif } @@ -209,14 +205,11 @@ void NixUtils::setLaunchAtStartup(bool enable) void NixUtils::launchAtStartupRequested(uint response, const QVariantMap& results) { if (response > 0) { - qDebug() << "The interaction was cancelled"; + qDebug() << "DBus Error: the request to autostart was cancelled."; return; } - bool isLauchedAtStartup = results["autostart"].value(); - qDebug() << "The autostart value is set to:" << isLauchedAtStartup; -#if defined(KEEPASSXC_DIST_FLATPAK) - config()->set(Config::GUI_LaunchAtStartup, isLauchedAtStartup); -#endif + + config()->set(Config::GUI_LaunchAtStartup, results["autostart"].value()); } bool NixUtils::isCapslockEnabled() @@ -242,6 +235,12 @@ bool NixUtils::isCapslockEnabled() return false; } +void NixUtils::setUserInputProtection(bool enable) +{ + // Linux does not support this feature + Q_UNUSED(enable) +} + void NixUtils::registerNativeEventFilter() { qApp->installNativeEventFilter(this); @@ -378,3 +377,37 @@ void NixUtils::setColorScheme(QDBusVariant value) m_systemColorschemePrefExists = true; emit interfaceThemeChanged(); } + +quint64 NixUtils::getProcessStartTime() const +{ + QString processStatPath = QString("/proc/%1/stat").arg(QCoreApplication::applicationPid()); + QFile processStatFile(processStatPath); + + if (!processStatFile.open(QIODevice::ReadOnly | QIODevice::Text)) { + qDebug() << "nixutils: failed to open " << processStatPath; + return 0; + } + + QTextStream processStatStream(&processStatFile); + QString processStatInfo = processStatStream.readLine(); + processStatFile.close(); + + auto startIndex = processStatInfo.lastIndexOf(')'); + if (startIndex != -1) { + auto tokens = processStatInfo.midRef(startIndex + 2).split(' '); + if (tokens.size() >= 20) { + bool ok; + auto time = tokens[19].toULongLong(&ok); + if (!ok) { + qDebug() << "nixutils: failed to convert " << tokens[19] << " to an integer in " << processStatPath; + return 0; + } + return time; + } + qDebug() << "nixutils: failed to find at least 20 values in " << processStatPath; + return 0; + } + + qDebug() << "nixutils: failed to find ')' in " << processStatPath; + return 0; +} diff --git a/src/gui/osutils/nixutils/NixUtils.h b/src/gui/osutils/nixutils/NixUtils.h index ee6d46dc3..9be835ff9 100644 --- a/src/gui/osutils/nixutils/NixUtils.h +++ b/src/gui/osutils/nixutils/NixUtils.h @@ -35,6 +35,7 @@ public: bool isLaunchAtStartupEnabled() const override; void setLaunchAtStartup(bool enable) override; bool isCapslockEnabled() override; + void setUserInputProtection(bool enable) override; void registerNativeEventFilter() override; @@ -49,6 +50,8 @@ public: return false; } + quint64 getProcessStartTime() const; + private slots: void handleColorSchemeRead(QDBusVariant value); void handleColorSchemeChanged(QString ns, QString key, QDBusVariant value); @@ -81,7 +84,7 @@ private: PreferLight }; ColorschemePref m_systemColorschemePref = ColorschemePref::PreferNone; - bool m_systemColorschemePrefExists; + bool m_systemColorschemePrefExists = false; void setColorScheme(QDBusVariant value); diff --git a/src/gui/osutils/nixutils/ScreenLockListenerDBus.cpp b/src/gui/osutils/nixutils/ScreenLockListenerDBus.cpp index be9b59fd1..1da87b997 100644 --- a/src/gui/osutils/nixutils/ScreenLockListenerDBus.cpp +++ b/src/gui/osutils/nixutils/ScreenLockListenerDBus.cpp @@ -91,7 +91,7 @@ void ScreenLockListenerDBus::login1SessionObjectReceived(QDBusMessage response) qDebug() << "org.freedesktop.login1.Manager.GetSession did not return a QDBusObjectPath"; return; } - QDBusObjectPath path = arg0.value(); + auto path = arg0.value(); QDBusConnection systemBus = QDBusConnection::systemBus(); systemBus.connect("", // service diff --git a/src/gui/osutils/winutils/DeviceListenerWin.cpp b/src/gui/osutils/winutils/DeviceListenerWin.cpp index dfd1b610d..408bf9d06 100644 --- a/src/gui/osutils/winutils/DeviceListenerWin.cpp +++ b/src/gui/osutils/winutils/DeviceListenerWin.cpp @@ -56,6 +56,7 @@ void DeviceListenerWin::registerHotplugCallback(bool arrived, regex += QString("PID_%1&").arg(productId, 0, 16).toUpper(); } } + regex += QString(".*$"); // Qt won't match otherwise m_deviceIdMatch = QRegularExpression(regex); DEV_BROADCAST_DEVICEINTERFACE_W notificationFilter{ diff --git a/src/gui/osutils/winutils/WinUtils.cpp b/src/gui/osutils/winutils/WinUtils.cpp index 188b91348..a15976932 100644 --- a/src/gui/osutils/winutils/WinUtils.cpp +++ b/src/gui/osutils/winutils/WinUtils.cpp @@ -136,6 +136,12 @@ bool WinUtils::isCapslockEnabled() return GetKeyState(VK_CAPITAL) == 1; } +void WinUtils::setUserInputProtection(bool enable) +{ + // Windows does not support this feature + Q_UNUSED(enable) +} + bool WinUtils::isHighContrastMode() const { QSettings settings(R"(HKEY_CURRENT_USER\Control Panel\Accessibility\HighContrast)", QSettings::NativeFormat); @@ -234,6 +240,8 @@ WORD WinUtils::qtToNativeKeyCode(Qt::Key key) return VK_SHIFT; // 0x10 case Qt::Key_Control: return VK_CONTROL; // 0x11 + case Qt::Key_Alt: + return VK_MENU; // 0x12 case Qt::Key_Pause: return VK_PAUSE; // 0x13 case Qt::Key_CapsLock: diff --git a/src/gui/osutils/winutils/WinUtils.h b/src/gui/osutils/winutils/WinUtils.h index 9e4492a5f..9278c9d60 100644 --- a/src/gui/osutils/winutils/WinUtils.h +++ b/src/gui/osutils/winutils/WinUtils.h @@ -44,6 +44,7 @@ public: bool isLaunchAtStartupEnabled() const override; void setLaunchAtStartup(bool enable) override; bool isCapslockEnabled() override; + void setUserInputProtection(bool enable) override; bool isHighContrastMode() const; void registerNativeEventFilter() override; diff --git a/src/gui/passkeys/PasskeyExportDialog.ui b/src/gui/passkeys/PasskeyExportDialog.ui old mode 100755 new mode 100644 diff --git a/src/gui/passkeys/PasskeyExporter.cpp b/src/gui/passkeys/PasskeyExporter.cpp index 315825b4b..4ff84e5f8 100644 --- a/src/gui/passkeys/PasskeyExporter.cpp +++ b/src/gui/passkeys/PasskeyExporter.cpp @@ -21,6 +21,7 @@ #include "browser/BrowserPasskeys.h" #include "browser/PasskeyUtils.h" #include "core/Entry.h" +#include "core/EntryAttributes.h" #include "core/Tools.h" #include "gui/MessageBox.h" #include @@ -94,12 +95,12 @@ void PasskeyExporter::exportSelectedEntry(const Entry* entry, const QString& fol } QJsonObject passkeyObject; - passkeyObject["relyingParty"] = entry->attributes()->value(BrowserPasskeys::KPEX_PASSKEY_RELYING_PARTY); + passkeyObject["relyingParty"] = entry->attributes()->value(EntryAttributes::KPEX_PASSKEY_RELYING_PARTY); passkeyObject["url"] = entry->url(); passkeyObject["username"] = passkeyUtils()->getUsernameFromEntry(entry); passkeyObject["credentialId"] = passkeyUtils()->getCredentialIdFromEntry(entry); - passkeyObject["userHandle"] = entry->attributes()->value(BrowserPasskeys::KPEX_PASSKEY_USER_HANDLE); - passkeyObject["privateKey"] = entry->attributes()->value(BrowserPasskeys::KPEX_PASSKEY_PRIVATE_KEY_PEM); + passkeyObject["userHandle"] = entry->attributes()->value(EntryAttributes::KPEX_PASSKEY_USER_HANDLE); + passkeyObject["privateKey"] = entry->attributes()->value(EntryAttributes::KPEX_PASSKEY_PRIVATE_KEY_PEM); QJsonDocument document(passkeyObject); if (passkeyFile.write(document.toJson()) < 0) { diff --git a/src/gui/passkeys/PasskeyImportDialog.ui b/src/gui/passkeys/PasskeyImportDialog.ui old mode 100755 new mode 100644 diff --git a/src/gui/passkeys/PasskeyImporter.cpp b/src/gui/passkeys/PasskeyImporter.cpp index 22435b99e..df4042069 100644 --- a/src/gui/passkeys/PasskeyImporter.cpp +++ b/src/gui/passkeys/PasskeyImporter.cpp @@ -39,7 +39,7 @@ void PasskeyImporter::importPasskey(QSharedPointer& database, Entry* e { auto filter = QString("%1 (*.passkey);;%2 (*)").arg(tr("Passkey file"), tr("All files")); auto fileName = - fileDialog()->getOpenFileName(nullptr, tr("Open passkey file"), FileDialog::getLastDir("passkey"), filter); + fileDialog()->getOpenFileName(m_parent, tr("Open passkey file"), FileDialog::getLastDir("passkey"), filter); if (fileName.isEmpty()) { return; } @@ -68,20 +68,16 @@ void PasskeyImporter::importSelectedFile(QFile& file, QSharedPointer& } const auto privateKey = passkeyObject["privateKey"].toString(); - const auto missingKeys = Tools::getMissingValuesFromList(passkeyObject.keys(), - QStringList() << "relyingParty" - << "url" - << "username" - << "credentialId" - << "userHandle" - << "privateKey"); + const auto missingKeys = Tools::getMissingValuesFromList( + passkeyObject.keys(), + QStringList() << "relyingParty" << "url" << "username" << "credentialId" << "userHandle" << "privateKey"); if (!missingKeys.isEmpty()) { MessageBox::information(m_parent, tr("Cannot import passkey"), tr("Cannot import passkey file \"%1\".\nThe following data is missing:\n%2") .arg(file.fileName(), missingKeys.join(", "))); - } else if (!privateKey.startsWith("-----BEGIN PRIVATE KEY-----") - || !privateKey.trimmed().endsWith("-----END PRIVATE KEY-----")) { + } else if (!privateKey.startsWith(EntryAttributes::KPEX_PASSKEY_PRIVATE_KEY_START) + || !privateKey.trimmed().endsWith(EntryAttributes::KPEX_PASSKEY_PRIVATE_KEY_END)) { MessageBox::information( m_parent, tr("Cannot import passkey"), diff --git a/src/gui/remote/DatabaseSettingsWidgetRemote.cpp b/src/gui/remote/DatabaseSettingsWidgetRemote.cpp new file mode 100644 index 000000000..f66edba7e --- /dev/null +++ b/src/gui/remote/DatabaseSettingsWidgetRemote.cpp @@ -0,0 +1,209 @@ +/* + * Copyright (C) 2023 KeePassXC Team + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 or (at your option) + * version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "DatabaseSettingsWidgetRemote.h" +#include "ui_DatabaseSettingsWidgetRemote.h" + +#include "core/Global.h" +#include "core/Metadata.h" + +#include "RemoteHandler.h" +#include "RemoteSettings.h" +#include "gui/MessageBox.h" + +DatabaseSettingsWidgetRemote::DatabaseSettingsWidgetRemote(QWidget* parent) + : DatabaseSettingsWidget(parent) + , m_remoteSettings(new RemoteSettings(nullptr, this)) + , m_ui(new Ui::DatabaseSettingsWidgetRemote()) +{ + m_ui->setupUi(this); + m_ui->messageWidget->setHidden(true); + + connect(m_ui->saveSettingsButton, &QPushButton::clicked, this, &DatabaseSettingsWidgetRemote::saveCurrentSettings); + connect( + m_ui->removeSettingsButton, &QPushButton::clicked, this, &DatabaseSettingsWidgetRemote::removeCurrentSettings); + connect(m_ui->settingsListWidget, + &QListWidget::itemSelectionChanged, + this, + &DatabaseSettingsWidgetRemote::editCurrentSettings); + connect(m_ui->testDownloadCommandButton, &QPushButton::clicked, this, &DatabaseSettingsWidgetRemote::testDownload); + + auto setModified = [this]() { m_modified = true; }; + connect(m_ui->nameLineEdit, &QLineEdit::textChanged, setModified); + connect(m_ui->downloadCommand, &QLineEdit::textChanged, setModified); + connect(m_ui->inputForDownload, &QPlainTextEdit::textChanged, setModified); + connect(m_ui->downloadTimeoutSec, QOverload::of(&QSpinBox::valueChanged), setModified); + connect(m_ui->uploadCommand, &QLineEdit::textChanged, setModified); + connect(m_ui->inputForUpload, &QPlainTextEdit::textChanged, setModified); + connect(m_ui->uploadTimeoutSec, QOverload::of(&QSpinBox::valueChanged), setModified); +} + +DatabaseSettingsWidgetRemote::~DatabaseSettingsWidgetRemote() = default; + +void DatabaseSettingsWidgetRemote::initialize() +{ + clearFields(); + m_remoteSettings->setDatabase(m_db); + updateSettingsList(); + if (m_ui->settingsListWidget->count() > 0) { + m_ui->settingsListWidget->setCurrentRow(0); + m_ui->removeSettingsButton->setEnabled(true); + } else { + m_ui->removeSettingsButton->setDisabled(true); + } +} + +void DatabaseSettingsWidgetRemote::uninitialize() +{ +} + +bool DatabaseSettingsWidgetRemote::saveSettings() +{ + if (m_modified) { + auto ans = MessageBox::question(this, + tr("Save Remote Settings"), + tr("You have unsaved changes. Do you want to save them?"), + MessageBox::Save | MessageBox::Discard | MessageBox::Cancel, + MessageBox::Save); + if (ans == MessageBox::Save) { + saveCurrentSettings(); + } else if (ans == MessageBox::Cancel) { + return false; + } + } + + m_remoteSettings->saveSettings(); + return true; +} + +void DatabaseSettingsWidgetRemote::saveCurrentSettings() +{ + QString name = m_ui->nameLineEdit->text(); + if (name.isEmpty()) { + m_ui->messageWidget->showMessage(tr("Name cannot be empty."), MessageWidget::Warning); + return; + } + + auto* params = new RemoteParams(); + params->name = m_ui->nameLineEdit->text(); + params->downloadCommand = m_ui->downloadCommand->text(); + params->downloadInput = m_ui->inputForDownload->toPlainText(); + params->downloadTimeoutMsec = m_ui->downloadTimeoutSec->value() * 1000; + params->uploadCommand = m_ui->uploadCommand->text(); + params->uploadInput = m_ui->inputForUpload->toPlainText(); + params->uploadTimeoutMsec = m_ui->uploadTimeoutSec->value() * 1000; + + m_remoteSettings->addRemoteParams(params); + updateSettingsList(); + + auto item = findItemByName(name); + m_ui->settingsListWidget->setCurrentItem(item); + m_ui->removeSettingsButton->setEnabled(true); + m_modified = false; +} + +QListWidgetItem* DatabaseSettingsWidgetRemote::findItemByName(const QString& name) +{ + return m_ui->settingsListWidget->findItems(name, Qt::MatchExactly).first(); +} + +void DatabaseSettingsWidgetRemote::removeCurrentSettings() +{ + m_remoteSettings->removeRemoteParams(m_ui->nameLineEdit->text()); + updateSettingsList(); + if (!m_remoteSettings->getAllRemoteParams().empty()) { + m_ui->settingsListWidget->setCurrentRow(0); + m_ui->removeSettingsButton->setEnabled(true); + } else { + clearFields(); + m_ui->removeSettingsButton->setDisabled(true); + } +} + +void DatabaseSettingsWidgetRemote::editCurrentSettings() +{ + if (!m_ui->settingsListWidget->currentItem()) { + return; + } + + QString name = m_ui->settingsListWidget->currentItem()->text(); + auto* params = m_remoteSettings->getRemoteParams(name); + if (!params) { + return; + } + + m_ui->nameLineEdit->setText(params->name); + m_ui->downloadCommand->setText(params->downloadCommand); + m_ui->inputForDownload->setPlainText(params->downloadInput); + m_ui->downloadTimeoutSec->setValue(params->downloadTimeoutMsec / 1000); + m_ui->uploadCommand->setText(params->uploadCommand); + m_ui->inputForUpload->setPlainText(params->uploadInput); + m_ui->uploadTimeoutSec->setValue(params->uploadTimeoutMsec / 1000); + m_modified = false; +} + +void DatabaseSettingsWidgetRemote::updateSettingsList() +{ + m_ui->settingsListWidget->clear(); + for (auto params : m_remoteSettings->getAllRemoteParams()) { + auto* item = new QListWidgetItem(m_ui->settingsListWidget); + item->setText(params->name); + m_ui->settingsListWidget->addItem(item); + } +} + +void DatabaseSettingsWidgetRemote::clearFields() +{ + m_ui->nameLineEdit->setText(""); + m_ui->downloadCommand->setText(""); + m_ui->inputForDownload->setPlainText(""); + m_ui->downloadTimeoutSec->setValue(10); + m_ui->uploadCommand->setText(""); + m_ui->inputForUpload->setPlainText(""); + m_ui->uploadTimeoutSec->setValue(10); + m_modified = false; +} + +void DatabaseSettingsWidgetRemote::testDownload() +{ + auto* params = new RemoteParams(); + params->name = m_ui->nameLineEdit->text(); + params->downloadCommand = m_ui->downloadCommand->text(); + params->downloadInput = m_ui->inputForDownload->toPlainText(); + params->downloadTimeoutMsec = m_ui->downloadTimeoutSec->value() * 1000; + + QScopedPointer remoteHandler(new RemoteHandler(this)); + if (params->downloadCommand.isEmpty()) { + m_ui->messageWidget->showMessage(tr("Download command cannot be empty."), MessageWidget::Warning); + return; + } + + RemoteHandler::RemoteResult result = remoteHandler->download(params); + if (!result.success) { + m_ui->messageWidget->showMessage(tr("Download failed with error: %1").arg(result.errorMessage), + MessageWidget::Error); + return; + } + + if (!QFile::exists(result.filePath)) { + m_ui->messageWidget->showMessage(tr("Download finished, but file %1 could not be found.").arg(result.filePath), + MessageWidget::Error); + return; + } + + m_ui->messageWidget->showMessage(tr("Download successful."), MessageWidget::Positive); +} diff --git a/src/gui/remote/DatabaseSettingsWidgetRemote.h b/src/gui/remote/DatabaseSettingsWidgetRemote.h new file mode 100644 index 000000000..6184e4bd9 --- /dev/null +++ b/src/gui/remote/DatabaseSettingsWidgetRemote.h @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2023 KeePassXC Team + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 or (at your option) + * version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef KEEPASSX_DATABASESETTINGSWIDGETREMOTE_H +#define KEEPASSX_DATABASESETTINGSWIDGETREMOTE_H + +#include "gui/dbsettings/DatabaseSettingsWidget.h" + +#include +#include + +class Database; +class RemoteSettings; + +namespace Ui +{ + class DatabaseSettingsWidgetRemote; +} + +class DatabaseSettingsWidgetRemote : public DatabaseSettingsWidget +{ + Q_OBJECT + +public: + explicit DatabaseSettingsWidgetRemote(QWidget* parent = nullptr); + Q_DISABLE_COPY(DatabaseSettingsWidgetRemote); + ~DatabaseSettingsWidgetRemote() override; + +public slots: + void initialize() override; + void uninitialize() override; + bool saveSettings() override; + +private slots: + void saveCurrentSettings(); + void removeCurrentSettings(); + void editCurrentSettings(); + void testDownload(); + +private: + void updateSettingsList(); + QListWidgetItem* findItemByName(const QString& name); + void clearFields(); + + QScopedPointer m_remoteSettings; + const QScopedPointer m_ui; + bool m_modified = false; +}; + +#endif // KEEPASSX_DATABASESETTINGSWIDGETREMOTE_H diff --git a/src/gui/remote/DatabaseSettingsWidgetRemote.ui b/src/gui/remote/DatabaseSettingsWidgetRemote.ui new file mode 100644 index 000000000..1ab5d8b8f --- /dev/null +++ b/src/gui/remote/DatabaseSettingsWidgetRemote.ui @@ -0,0 +1,306 @@ + + + DatabaseSettingsWidgetRemote + + + + 0 + 0 + 652 + 516 + + + + + 0 + 0 + + + + + 450 + 0 + + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 0 + 0 + + + + + + + + Sync Commands + + + + + + + + + + + Qt::LeftToRight + + + Remove + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + + + + + 0 + 0 + + + + Command Settings + + + + QLayout::SetMinimumSize + + + + + + + Name + + + + + + + + + + + + Save + + + + + + + + + 0 + + + + Download + + + + + + Input: + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop + + + + + + + Command: + + + + + + + Download input field + + + e.g.: +get DatabaseOnRemote.kdbx {TEMP_DATABASE} +exit +--- +{TEMP_DATABASE} is used as placeholder to store the database in a temporary location +The command has to exit. In case of `sftp` as last command `exit` has to be sent + + + + + + + + + + Download command field + + + e.g.: "sftp user@hostname" or "scp user@hostname:DatabaseOnRemote.kdbx {TEMP_DATABASE}" + + + + + + + Test + + + + + + + + + Timeout: + + + + + + + seconds + + + 1 + + + 300 + + + 10 + + + + + + + + Upload + + + + + + Upload input field + + + e.g.: +put {TEMP_DATABASE} DatabaseOnRemote.kdbx +exit +--- +{TEMP_DATABASE} is used as placeholder to store the database in a temporary location +The command has to exit. In case of `sftp` as last command `exit` has to be sent + + + + + + + + Input: + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop + + + + + + + Upload command field + + + e.g.: "sftp user@hostname" or "scp {TEMP_DATABASE} user@hostname:DatabaseOnRemote.kdbx" + + + + + + + Command: + + + + + + + Timeout: + + + + + + + seconds + + + 1 + + + 300 + + + 10 + + + + + + + + + + + + + + + + + MessageWidget + QWidget +
    gui/MessageWidget.h
    + 1 +
    +
    + + +
    diff --git a/src/gui/remote/RemoteHandler.cpp b/src/gui/remote/RemoteHandler.cpp new file mode 100644 index 000000000..c3bb857dd --- /dev/null +++ b/src/gui/remote/RemoteHandler.cpp @@ -0,0 +1,145 @@ +/* + * Copyright (C) 2023 KeePassXC Team + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 or (at your option) + * version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "RemoteHandler.h" + +#include "RemoteProcess.h" +#include "RemoteSettings.h" + +#include "core/AsyncTask.h" +#include "core/Database.h" + +namespace +{ + QString getTempFileLocation() + { + QString uuid = QUuid::createUuid().toString().remove(0, 1); + uuid.chop(1); + return QDir::toNativeSeparators(QDir::temp().absoluteFilePath("RemoteDatabase-" + uuid + ".kdbx")); + } +} // namespace + +std::function(QObject*)> RemoteHandler::m_createRemoteProcess([](QObject* parent) { + return QScopedPointer(new RemoteProcess(parent)); +}); + +RemoteHandler::RemoteHandler(QObject* parent) + : QObject(parent) +{ +} + +void RemoteHandler::setRemoteProcessFunc(std::function(QObject*)> func) +{ + m_createRemoteProcess = std::move(func); +} + +RemoteHandler::RemoteResult RemoteHandler::download(const RemoteParams* params) +{ + return AsyncTask::runAndWaitForFuture([params] { + RemoteResult result; + if (!params) { + result.success = false; + result.errorMessage = tr("Invalid download parameters provided."); + return result; + } + + auto filePath = getTempFileLocation(); + auto remoteProcess = m_createRemoteProcess(nullptr); // use nullptr parent, otherwise there is a warning + remoteProcess->setTempFileLocation(filePath); + remoteProcess->start(params->downloadCommand); + if (!params->downloadInput.isEmpty()) { + remoteProcess->write(params->downloadInput + "\n"); + remoteProcess->waitForBytesWritten(); + remoteProcess->closeWriteChannel(); + } + + bool finished = remoteProcess->waitForFinished(params->downloadTimeoutMsec); + int statusCode = remoteProcess->exitCode(); + + // TODO: For future use + result.stdOutput = remoteProcess->readOutput(); + result.stdError = remoteProcess->readError(); + + if (finished && statusCode == 0) { + // Check if the file actually downloaded + QFileInfo fileInfo(filePath); + if (!fileInfo.exists() || fileInfo.size() == 0) { + result.success = false; + result.errorMessage = tr("Command `%1` failed to download database.").arg(params->downloadCommand); + } else { + result.success = true; + result.filePath = filePath; + } + } else if (finished) { + result.success = false; + result.errorMessage = + tr("Command `%1` exited with status code: %2").arg(params->downloadCommand).arg(statusCode); + } else { + remoteProcess->kill(); + result.success = false; + result.errorMessage = + tr("Command `%1` did not finish in time. Process was killed.").arg(params->downloadCommand); + } + + return result; + }); +} + +RemoteHandler::RemoteResult RemoteHandler::upload(const QString& filePath, const RemoteParams* params) +{ + return AsyncTask::runAndWaitForFuture([filePath, params] { + RemoteResult result; + if (!params) { + result.success = false; + result.errorMessage = tr("Invalid database pointer or upload parameters provided."); + return result; + } + + auto remoteProcess = m_createRemoteProcess(nullptr); // use nullptr parent, otherwise there is a warning + remoteProcess->setTempFileLocation(filePath); + remoteProcess->start(params->uploadCommand); + if (!params->uploadInput.isEmpty()) { + remoteProcess->write(params->uploadInput + "\n"); + remoteProcess->waitForBytesWritten(); + remoteProcess->closeWriteChannel(); + } + + bool finished = remoteProcess->waitForFinished(params->uploadTimeoutMsec); + int statusCode = remoteProcess->exitCode(); + + // TODO: For future use + result.stdOutput = remoteProcess->readOutput(); + result.stdError = remoteProcess->readError(); + + if (finished && statusCode == 0) { + result.success = true; + } else if (finished) { + result.success = false; + result.errorMessage = tr("Failed to upload merged database. Command `%1` exited with status code: %2") + .arg(params->uploadCommand) + .arg(statusCode); + } else { + remoteProcess->kill(); + result.success = false; + result.errorMessage = + tr("Failed to upload merged database. Command `%1` did not finish in time. Process was killed.") + .arg(params->uploadCommand); + } + + return result; + }); +} diff --git a/src/gui/remote/RemoteHandler.h b/src/gui/remote/RemoteHandler.h new file mode 100644 index 000000000..a46ee8c19 --- /dev/null +++ b/src/gui/remote/RemoteHandler.h @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2023 KeePassXC Team + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 or (at your option) + * version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef KEEPASSXC_REMOTEHANDLER_H +#define KEEPASSXC_REMOTEHANDLER_H + +#include + +class Database; +class RemoteProcess; +struct RemoteParams; + +class RemoteHandler : public QObject +{ + Q_OBJECT + +public: + explicit RemoteHandler(QObject* parent = nullptr); + ~RemoteHandler() override = default; + + struct RemoteResult + { + bool success; + QString errorMessage; + QString filePath; + QString stdOutput; + QString stdError; + }; + + RemoteResult download(const RemoteParams* params); + RemoteResult upload(const QString& filePath, const RemoteParams* params); + + // Used for testing only + static void setRemoteProcessFunc(std::function(QObject*)> func); + +private: + static std::function(QObject*)> m_createRemoteProcess; + static QString m_tempFileLocation; + + Q_DISABLE_COPY(RemoteHandler) +}; + +#endif // KEEPASSXC_REMOTEHANDLER_H diff --git a/src/gui/remote/RemoteProcess.cpp b/src/gui/remote/RemoteProcess.cpp new file mode 100644 index 000000000..6b2f60717 --- /dev/null +++ b/src/gui/remote/RemoteProcess.cpp @@ -0,0 +1,98 @@ +/* + * Copyright (C) 2023 KeePassXC Team + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 or (at your option) + * version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "RemoteProcess.h" + +#include +#include + +RemoteProcess::RemoteProcess(QObject* parent) + : m_process(new QProcess(parent)) +{ +} + +RemoteProcess::~RemoteProcess() +{ +} + +void RemoteProcess::setTempFileLocation(const QString& tempFile) +{ + m_tempFileLocation = tempFile; +} + +void RemoteProcess::start(const QString& command) +{ + const QString commandResolved = resolveTemplateVariables(command); +#if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0) + QStringList cmdList = QProcess::splitCommand(commandResolved); + if (!cmdList.isEmpty()) { + const QString program = cmdList.takeFirst(); + m_process->start(program, cmdList); + } +#else + m_process->start(resolveTemplateVariables(commandResolved)); +#endif + + m_process->waitForStarted(); +} + +qint64 RemoteProcess::write(const QString& input) +{ + auto resolved = resolveTemplateVariables(input); + return m_process->write(resolved.toUtf8()); +} + +bool RemoteProcess::waitForBytesWritten() +{ + return m_process->waitForBytesWritten(); +} + +void RemoteProcess::closeWriteChannel() +{ + m_process->closeWriteChannel(); +} + +bool RemoteProcess::waitForFinished(int msecs) +{ + return m_process->waitForFinished(msecs); +} + +int RemoteProcess::exitCode() const +{ + return m_process->exitCode(); +} + +QString RemoteProcess::readOutput() +{ + return m_process->readAllStandardOutput(); +} + +QString RemoteProcess::readError() +{ + return m_process->readAllStandardError(); +} + +void RemoteProcess::kill() const +{ + m_process->kill(); +} + +QString RemoteProcess::resolveTemplateVariables(const QString& input) const +{ + QString resolved = input; + return resolved.replace("{TEMP_DATABASE}", m_tempFileLocation); +} diff --git a/src/gui/remote/RemoteProcess.h b/src/gui/remote/RemoteProcess.h new file mode 100644 index 000000000..fb43d0430 --- /dev/null +++ b/src/gui/remote/RemoteProcess.h @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2023 KeePassXC Team + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 or (at your option) + * version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef KEEPASSXC_REMOTEPROCESS_H +#define KEEPASSXC_REMOTEPROCESS_H + +#include + +class RemoteProcess +{ +public: + explicit RemoteProcess(QObject* parent); + virtual ~RemoteProcess(); + + virtual void setTempFileLocation(const QString& tempFile); + + virtual void start(const QString& command); + virtual qint64 write(const QString& input); + virtual bool waitForBytesWritten(); + virtual void closeWriteChannel(); + virtual bool waitForFinished(int msecs); + virtual QString readOutput(); + virtual QString readError(); + virtual int exitCode() const; + void kill() const; + +protected: + QString m_tempFileLocation; + +private: + QString resolveTemplateVariables(const QString& input) const; + + QScopedPointer m_process; +}; + +#endif // KEEPASSXC_REMOTEPROCESS_H diff --git a/src/gui/remote/RemoteSettings.cpp b/src/gui/remote/RemoteSettings.cpp new file mode 100644 index 000000000..f5af3b1e1 --- /dev/null +++ b/src/gui/remote/RemoteSettings.cpp @@ -0,0 +1,120 @@ +/* + * Copyright (C) 2023 KeePassXC Team + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 or (at your option) + * version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "RemoteSettings.h" + +#include "core/Database.h" +#include "core/Metadata.h" + +#include +#include +#include +#include + +RemoteSettings::RemoteSettings(const QSharedPointer& db, QObject* parent) + : QObject(parent) +{ + setDatabase(db); +} + +RemoteSettings::~RemoteSettings() = default; + +void RemoteSettings::setDatabase(const QSharedPointer& db) +{ + m_remoteParams.clear(); + m_db = db; + loadSettings(); +} + +void RemoteSettings::addRemoteParams(RemoteParams* params) +{ + if (params->name.isEmpty()) { + qWarning() << "RemoteSettings::addRemoteParams: Remote parameters name is empty"; + return; + } + m_remoteParams.insert(params->name, params); +} + +void RemoteSettings::removeRemoteParams(const QString& name) +{ + m_remoteParams.remove(name); +} + +RemoteParams* RemoteSettings::getRemoteParams(const QString& name) const +{ + if (m_remoteParams.contains(name)) { + return m_remoteParams.value(name); + } + return nullptr; +} + +QList RemoteSettings::getAllRemoteParams() const +{ + return m_remoteParams.values(); +} + +void RemoteSettings::loadSettings() +{ + if (m_db) { + fromConfig(m_db->metadata()->customData()->value(CustomData::RemoteProgramSettings)); + } +} + +void RemoteSettings::saveSettings() const +{ + if (m_db) { + m_db->metadata()->customData()->set(CustomData::RemoteProgramSettings, toConfig()); + } +} + +QString RemoteSettings::toConfig() const +{ + QJsonArray config; + for (const auto params : m_remoteParams.values()) { + QJsonObject object; + object["name"] = params->name; + object["downloadCommand"] = params->downloadCommand; + object["downloadCommandInput"] = params->downloadInput; + object["downloadTimeoutMsec"] = params->downloadTimeoutMsec; + object["uploadCommand"] = params->uploadCommand; + object["uploadCommandInput"] = params->uploadInput; + object["uploadTimeoutMsec"] = params->uploadTimeoutMsec; + config << object; + } + QJsonDocument doc(config); + return doc.toJson(QJsonDocument::Compact); +} + +void RemoteSettings::fromConfig(const QString& data) +{ + m_remoteParams.clear(); + + QJsonDocument json = QJsonDocument::fromJson(data.toUtf8()); + for (const auto& item : json.array().toVariantList()) { + auto itemMap = item.toMap(); + auto* params = new RemoteParams(); + params->name = itemMap["name"].toString(); + params->downloadCommand = itemMap["downloadCommand"].toString(); + params->downloadInput = itemMap["downloadCommandInput"].toString(); + params->downloadTimeoutMsec = itemMap.value("downloadTimeoutMsec", 10000).toInt(); + params->uploadCommand = itemMap["uploadCommand"].toString(); + params->uploadInput = itemMap["uploadCommandInput"].toString(); + params->uploadTimeoutMsec = itemMap.value("uploadTimeoutMsec", 10000).toInt(); + + m_remoteParams.insert(params->name, params); + } +} diff --git a/src/gui/remote/RemoteSettings.h b/src/gui/remote/RemoteSettings.h new file mode 100644 index 000000000..4b414494c --- /dev/null +++ b/src/gui/remote/RemoteSettings.h @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2024 KeePassXC Team + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 or (at your option) + * version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef KEEPASSXC_REMOTESETTINGS_H +#define KEEPASSXC_REMOTESETTINGS_H + +#include +#include + +class Database; + +struct RemoteParams +{ + QString name; + QString downloadCommand; + QString downloadInput; + int downloadTimeoutMsec; + QString uploadCommand; + QString uploadInput; + int uploadTimeoutMsec; +}; +Q_DECLARE_METATYPE(RemoteParams) + +class RemoteSettings : public QObject +{ + Q_OBJECT +public: + explicit RemoteSettings(const QSharedPointer& db, QObject* parent = nullptr); + ~RemoteSettings() override; + + void setDatabase(const QSharedPointer& db); + + void addRemoteParams(RemoteParams* params); + void removeRemoteParams(const QString& name); + RemoteParams* getRemoteParams(const QString& name) const; + QList getAllRemoteParams() const; + + void loadSettings(); + void saveSettings() const; + +private: + void fromConfig(const QString& data); + QString toConfig() const; + + QHash m_remoteParams; + QSharedPointer m_db; +}; + +#endif // KEEPASSXC_REMOTESETTINGS_H diff --git a/src/gui/reports/ReportsDialog.cpp b/src/gui/reports/ReportsDialog.cpp index 9c361116f..1d32c2322 100644 --- a/src/gui/reports/ReportsDialog.cpp +++ b/src/gui/reports/ReportsDialog.cpp @@ -34,9 +34,6 @@ #include "core/Global.h" #include "core/Group.h" -#ifdef Q_OS_MACOS -#include "touchid/TouchID.h" -#endif class ReportsDialog::ExtraPage { @@ -109,9 +106,7 @@ ReportsDialog::ReportsDialog(QWidget* parent) connect(m_editEntryWidget, SIGNAL(editFinished(bool)), SLOT(switchToMainView(bool))); } -ReportsDialog::~ReportsDialog() -{ -} +ReportsDialog::~ReportsDialog() = default; void ReportsDialog::load(const QSharedPointer& db) { @@ -133,14 +128,23 @@ void ReportsDialog::addPage(QSharedPointer page) m_ui->categoryList->setCurrentCategory(category); } -#ifdef WITH_XC_BROWSER_PASSKEYS void ReportsDialog::activatePasskeysPage() { +#ifdef WITH_XC_BROWSER_PASSKEYS m_ui->stackedWidget->setCurrentWidget(m_passkeysPage->m_passkeysWidget); auto index = m_ui->stackedWidget->currentIndex(); m_ui->categoryList->setCurrentCategory(index); -} #endif +} + +bool ReportsDialog::onPassKeysPage() +{ +#ifdef WITH_XC_BROWSER_PASSKEYS + return m_ui->stackedWidget->currentWidget() == m_passkeysPage->m_passkeysWidget; +#else + return false; +#endif +} void ReportsDialog::reject() { @@ -149,7 +153,7 @@ void ReportsDialog::reject() void ReportsDialog::entryActivationSignalReceived(Entry* entry) { - m_sender = static_cast(sender()); + m_sender = qobject_cast(sender()); m_editEntryWidget->loadEntry(entry, false, false, entry->group()->hierarchy().join(" > "), m_db); m_ui->stackedWidget->setCurrentWidget(m_editEntryWidget); } diff --git a/src/gui/reports/ReportsDialog.h b/src/gui/reports/ReportsDialog.h index 8179ae283..abeaab481 100644 --- a/src/gui/reports/ReportsDialog.h +++ b/src/gui/reports/ReportsDialog.h @@ -44,9 +44,7 @@ namespace Ui class IReportsPage { public: - virtual ~IReportsPage() - { - } + virtual ~IReportsPage() = default; virtual QString name() = 0; virtual QIcon icon() = 0; virtual QWidget* createWidget() = 0; @@ -65,9 +63,8 @@ public: void load(const QSharedPointer& db); void addPage(QSharedPointer page); -#ifdef WITH_XC_BROWSER_PASSKEYS void activatePasskeysPage(); -#endif + bool onPassKeysPage(); signals: void editFinished(bool accepted); diff --git a/src/gui/reports/ReportsPageStatistics.cpp b/src/gui/reports/ReportsPageStatistics.cpp index f7fb2f170..57497d19c 100644 --- a/src/gui/reports/ReportsPageStatistics.cpp +++ b/src/gui/reports/ReportsPageStatistics.cpp @@ -37,12 +37,12 @@ QWidget* ReportsPageStatistics::createWidget() void ReportsPageStatistics::loadSettings(QWidget* widget, QSharedPointer db) { - ReportsWidgetStatistics* settingsWidget = reinterpret_cast(widget); + auto settingsWidget = reinterpret_cast(widget); settingsWidget->loadSettings(db); } void ReportsPageStatistics::saveSettings(QWidget* widget) { - ReportsWidgetStatistics* settingsWidget = reinterpret_cast(widget); + auto settingsWidget = reinterpret_cast(widget); settingsWidget->saveSettings(); } diff --git a/src/gui/reports/ReportsWidget.cpp b/src/gui/reports/ReportsWidget.cpp index 184434116..c822f4782 100644 --- a/src/gui/reports/ReportsWidget.cpp +++ b/src/gui/reports/ReportsWidget.cpp @@ -22,9 +22,7 @@ ReportsWidget::ReportsWidget(QWidget* parent) { } -ReportsWidget::~ReportsWidget() -{ -} +ReportsWidget::~ReportsWidget() = default; /** * Load the database to be configured by this page and initialize the page. diff --git a/src/gui/reports/ReportsWidget.h b/src/gui/reports/ReportsWidget.h index 59609acf9..c80c5eb65 100644 --- a/src/gui/reports/ReportsWidget.h +++ b/src/gui/reports/ReportsWidget.h @@ -18,7 +18,7 @@ #ifndef KEEPASSXC_REPORTSWIDGET_H #define KEEPASSXC_REPORTSWIDGET_H -#include "gui/settings/SettingsWidget.h" +#include "gui/SettingsWidget.h" class Database; diff --git a/src/gui/reports/ReportsWidgetBrowserStatistics.cpp b/src/gui/reports/ReportsWidgetBrowserStatistics.cpp index a7724a7e4..63267d77f 100644 --- a/src/gui/reports/ReportsWidgetBrowserStatistics.cpp +++ b/src/gui/reports/ReportsWidgetBrowserStatistics.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2021 KeePassXC Team + * Copyright (C) 2024 KeePassXC Team * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -27,7 +27,6 @@ #include "gui/styles/StateColorPalette.h" #include -#include #include #include #include @@ -276,10 +275,25 @@ void ReportsWidgetBrowserStatistics::customMenuRequested(QPoint pos) }); } + // Create the "expire entry" menu item + const auto expEntry = new QAction(icons()->icon("entry-expire"), tr("Expire Entry(s)…", "", selected.size()), this); + menu->addAction(expEntry); + connect(expEntry, &QAction::triggered, this, &ReportsWidgetBrowserStatistics::expireSelectedEntries); + // Create the "delete entry" menu item - const auto delEntry = new QAction(icons()->icon("entry-delete"), tr("Delete Entry(s)…", "", selected.size()), this); - menu->addAction(delEntry); - connect(delEntry, &QAction::triggered, this, &ReportsWidgetBrowserStatistics::deleteSelectedEntries); + const auto deleteEntry = + new QAction(icons()->icon("entry-delete"), tr("Delete Entry(s)…", "", selected.size()), this); + menu->addAction(deleteEntry); + connect(deleteEntry, &QAction::triggered, this, &ReportsWidgetBrowserStatistics::deleteSelectedEntries); + + // Create the "delete plugin data" menu item + const auto deletePluginData = + new QAction(icons()->icon("entry-delete"), tr("Delete plugin data from Entry(s)…", "", selected.size()), this); + menu->addAction(deletePluginData); + connect(deletePluginData, + &QAction::triggered, + this, + &ReportsWidgetBrowserStatistics::deletePluginDataFromSelectedEntries); // Create the "exclude from reports" menu item const auto exclude = new QAction(icons()->icon("reports-exclude"), tr("Exclude from reports"), this); @@ -318,7 +332,7 @@ void ReportsWidgetBrowserStatistics::saveSettings() // Nothing to do - the tab is passive } -void ReportsWidgetBrowserStatistics::deleteSelectedEntries() +QList ReportsWidgetBrowserStatistics::getSelectedEntries() { QList selectedEntries; for (auto index : m_ui->browserStatisticsTableView->selectionModel()->selectedRows()) { @@ -328,8 +342,23 @@ void ReportsWidgetBrowserStatistics::deleteSelectedEntries() selectedEntries << entry; } } + return selectedEntries; +} +void ReportsWidgetBrowserStatistics::expireSelectedEntries() +{ + for (auto entry : getSelectedEntries()) { + entry->expireNow(); + } + + calculateBrowserStatistics(); +} + +void ReportsWidgetBrowserStatistics::deleteSelectedEntries() +{ + const auto& selectedEntries = getSelectedEntries(); bool permanent = !m_db->metadata()->recycleBinEnabled(); + if (GuiTools::confirmDeleteEntries(this, selectedEntries, permanent)) { GuiTools::deleteEntriesResolveReferences(this, selectedEntries, permanent); } @@ -337,6 +366,18 @@ void ReportsWidgetBrowserStatistics::deleteSelectedEntries() calculateBrowserStatistics(); } +void ReportsWidgetBrowserStatistics::deletePluginDataFromSelectedEntries() +{ + const auto& selectedEntries = getSelectedEntries(); + if (GuiTools::confirmDeletePluginData(this, selectedEntries)) { + for (auto& entry : selectedEntries) { + browserService()->removePluginData(entry); + } + } + + calculateBrowserStatistics(); +} + QMap ReportsWidgetBrowserStatistics::getBrowserConfigFromEntry(Entry* entry) const { QMap configList; @@ -372,3 +413,17 @@ QMap ReportsWidgetBrowserStatistics::getBrowserConfigFromE return configList; } + +QList ReportsWidgetBrowserStatistics::getSelectedEntries() const +{ + QList selectedEntries; + for (auto index : m_ui->browserStatisticsTableView->selectionModel()->selectedRows()) { + auto row = m_modelProxy->mapToSource(index).row(); + auto entry = m_rowToEntry[row].second; + if (entry) { + selectedEntries << entry; + } + } + + return selectedEntries; +} diff --git a/src/gui/reports/ReportsWidgetBrowserStatistics.h b/src/gui/reports/ReportsWidgetBrowserStatistics.h index 8aa6651ee..9b1cc7d60 100644 --- a/src/gui/reports/ReportsWidgetBrowserStatistics.h +++ b/src/gui/reports/ReportsWidgetBrowserStatistics.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2021 KeePassXC Team + * Copyright (C) 2024 KeePassXC Team * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -53,10 +53,14 @@ public slots: void calculateBrowserStatistics(); void emitEntryActivated(const QModelIndex& index); void customMenuRequested(QPoint); + QList getSelectedEntries(); + void expireSelectedEntries(); void deleteSelectedEntries(); + void deletePluginDataFromSelectedEntries(); private: void addStatisticsRow(bool hasUrls, bool hasSettings, Group*, Entry*, bool); + QList getSelectedEntries() const; QMap getBrowserConfigFromEntry(Entry* entry) const; QScopedPointer m_ui; diff --git a/src/gui/reports/ReportsWidgetHealthcheck.cpp b/src/gui/reports/ReportsWidgetHealthcheck.cpp index 9bf122f9d..1c34c2f36 100644 --- a/src/gui/reports/ReportsWidgetHealthcheck.cpp +++ b/src/gui/reports/ReportsWidgetHealthcheck.cpp @@ -158,40 +158,39 @@ ReportsWidgetHealthcheck::ReportsWidgetHealthcheck(QWidget* parent) new QShortcut(Qt::Key_Delete, this, SLOT(deleteSelectedEntries())); } -ReportsWidgetHealthcheck::~ReportsWidgetHealthcheck() -{ -} +ReportsWidgetHealthcheck::~ReportsWidgetHealthcheck() = default; void ReportsWidgetHealthcheck::addHealthRow(QSharedPointer health, Group* group, Entry* entry, bool excluded) { - QString descr, tip; + QString tip; + QString iconName = "lock-question"; QColor qualityColor; StateColorPalette statePalette; const auto quality = health->quality(); switch (quality) { case PasswordHealth::Quality::Bad: - descr = tr("Bad", "Password quality"); tip = tr("Bad — password must be changed"); + iconName = "lock-open-alert"; qualityColor = statePalette.color(StateColorPalette::HealthCritical); break; - case PasswordHealth::Quality::Poor: - descr = tr("Poor", "Password quality"); tip = tr("Poor — password should be changed"); + iconName = "lock-open-alert"; qualityColor = statePalette.color(StateColorPalette::HealthBad); break; case PasswordHealth::Quality::Weak: - descr = tr("Weak", "Password quality"); tip = tr("Weak — consider changing the password"); + iconName = "lock-open"; qualityColor = statePalette.color(StateColorPalette::HealthWeak); break; case PasswordHealth::Quality::Good: case PasswordHealth::Quality::Excellent: + iconName = "lock"; qualityColor = statePalette.color(StateColorPalette::HealthOk); break; } @@ -205,7 +204,7 @@ void ReportsWidgetHealthcheck::addHealthRow(QSharedPointer healt } auto row = QList(); - row << new QStandardItem(descr); + row << new QStandardItem(Icons::instance()->icon(iconName, true, qualityColor), ""); row << new QStandardItem(Icons::entryIconPixmap(entry), title); row << new QStandardItem(Icons::groupIconPixmap(group), group->hierarchy().join("/")); row << new QStandardItem(QString::number(health->score())); @@ -216,7 +215,6 @@ void ReportsWidgetHealthcheck::addHealthRow(QSharedPointer healt // invisible, it's just for screen readers etc. QBrush brush(qualityColor); row[0]->setForeground(brush); - row[0]->setBackground(brush); // Set tooltips row[0]->setToolTip(tip); @@ -240,6 +238,8 @@ void ReportsWidgetHealthcheck::loadSettings(QSharedPointer db) auto row = QList(); row << new QStandardItem(tr("Please wait, health data is being calculated…")); m_referencesModel->appendRow(row); + // Default sort by first column (health score) + m_ui->healthcheckTableView->sortByColumn(0, Qt::AscendingOrder); } void ReportsWidgetHealthcheck::showEvent(QShowEvent* event) @@ -255,6 +255,11 @@ void ReportsWidgetHealthcheck::showEvent(QShowEvent* event) void ReportsWidgetHealthcheck::calculateHealth() { + // Save current sort order before clearing the model so we can restore it later + int sortColumn = m_ui->healthcheckTableView->horizontalHeader()->sortIndicatorSection(); + Qt::SortOrder sortOrder = m_ui->healthcheckTableView->horizontalHeader()->sortIndicatorOrder(); + + // Safe to clear m_referencesModel->clear(); // Perform the health check @@ -279,9 +284,11 @@ void ReportsWidgetHealthcheck::calculateHealth() } else { m_referencesModel->setHorizontalHeaderLabels(QStringList() << tr("") << tr("Title") << tr("Path") << tr("Score") << tr("Reason")); - m_ui->healthcheckTableView->sortByColumn(0, Qt::AscendingOrder); } + // Restore sorting options that was stored before the model was cleared + m_ui->healthcheckTableView->sortByColumn(sortColumn, sortOrder); + m_ui->healthcheckTableView->resizeColumnsToContents(); m_ui->healthcheckTableView->horizontalHeader()->setSectionResizeMode(0, QHeaderView::Fixed); @@ -325,6 +332,11 @@ void ReportsWidgetHealthcheck::customMenuRequested(QPoint pos) }); } + // Create the "Expire entry" menu item + const auto expEntry = new QAction(icons()->icon("entry-expire"), tr("Expire Entry(s)…", "", selected.size()), this); + menu->addAction(expEntry); + connect(expEntry, &QAction::triggered, this, &ReportsWidgetHealthcheck::expireSelectedEntries); + // Create the "delete entry" menu item const auto delEntry = new QAction(icons()->icon("entry-delete"), tr("Delete Entry(s)…", "", selected.size()), this); menu->addAction(delEntry); @@ -367,7 +379,7 @@ void ReportsWidgetHealthcheck::saveSettings() // nothing to do - the tab is passive } -void ReportsWidgetHealthcheck::deleteSelectedEntries() +QList ReportsWidgetHealthcheck::getSelectedEntries() { QList selectedEntries; for (auto index : m_ui->healthcheckTableView->selectionModel()->selectedRows()) { @@ -377,7 +389,21 @@ void ReportsWidgetHealthcheck::deleteSelectedEntries() selectedEntries << entry; } } + return selectedEntries; +} +void ReportsWidgetHealthcheck::expireSelectedEntries() +{ + for (auto entry : getSelectedEntries()) { + entry->expireNow(); + } + + calculateHealth(); +} + +void ReportsWidgetHealthcheck::deleteSelectedEntries() +{ + QList selectedEntries = getSelectedEntries(); bool permanent = !m_db->metadata()->recycleBinEnabled(); if (GuiTools::confirmDeleteEntries(this, selectedEntries, permanent)) { GuiTools::deleteEntriesResolveReferences(this, selectedEntries, permanent); diff --git a/src/gui/reports/ReportsWidgetHealthcheck.h b/src/gui/reports/ReportsWidgetHealthcheck.h index 21d121b00..9a46b36b1 100644 --- a/src/gui/reports/ReportsWidgetHealthcheck.h +++ b/src/gui/reports/ReportsWidgetHealthcheck.h @@ -53,6 +53,8 @@ public slots: void calculateHealth(); void emitEntryActivated(const QModelIndex& index); void customMenuRequested(QPoint); + QList getSelectedEntries(); + void expireSelectedEntries(); void deleteSelectedEntries(); private: diff --git a/src/gui/reports/ReportsWidgetHibp.cpp b/src/gui/reports/ReportsWidgetHibp.cpp index 86be3d92f..a559208aa 100644 --- a/src/gui/reports/ReportsWidgetHibp.cpp +++ b/src/gui/reports/ReportsWidgetHibp.cpp @@ -29,6 +29,8 @@ #include #include +#include + namespace { class ReportSortProxyModel : public QSortFilterProxyModel @@ -79,9 +81,7 @@ ReportsWidgetHibp::ReportsWidgetHibp(QWidget* parent) new QShortcut(Qt::Key_Delete, this, SLOT(deleteSelectedEntries())); } -ReportsWidgetHibp::~ReportsWidgetHibp() -{ -} +ReportsWidgetHibp::~ReportsWidgetHibp() = default; void ReportsWidgetHibp::loadSettings(QSharedPointer db) { @@ -133,8 +133,8 @@ void ReportsWidgetHibp::makeHibpTable() } } - // Sort decending by the number the password has been exposed - qSort(items.begin(), items.end(), [](QPair& lhs, QPair& rhs) { + // Sort descending by the number the password has been exposed + std::sort(items.begin(), items.end(), [](QPair& lhs, QPair& rhs) { return lhs.second > rhs.second; }); @@ -374,6 +374,11 @@ void ReportsWidgetHibp::customMenuRequested(QPoint pos) }); } + // Create the "Expire entry" menu item + const auto expEntry = new QAction(icons()->icon("entry-expire"), tr("Expire Entry(s)…", "", selected.size()), this); + menu->addAction(expEntry); + connect(expEntry, &QAction::triggered, this, &ReportsWidgetHibp::expireSelectedEntries); + // Create the "delete entry" menu item const auto delEntry = new QAction(icons()->icon("entry-delete"), tr("Delete Entry(s)…", "", selected.size()), this); menu->addAction(delEntry); @@ -411,7 +416,7 @@ void ReportsWidgetHibp::customMenuRequested(QPoint pos) menu->popup(m_ui->hibpTableView->viewport()->mapToGlobal(pos)); } -void ReportsWidgetHibp::deleteSelectedEntries() +QList ReportsWidgetHibp::getSelectedEntries() { QList selectedEntries; for (auto index : m_ui->hibpTableView->selectionModel()->selectedRows()) { @@ -421,7 +426,21 @@ void ReportsWidgetHibp::deleteSelectedEntries() selectedEntries << entry; } } + return selectedEntries; +} +void ReportsWidgetHibp::expireSelectedEntries() +{ + for (auto entry : getSelectedEntries()) { + entry->expireNow(); + } + + makeHibpTable(); +} + +void ReportsWidgetHibp::deleteSelectedEntries() +{ + QList selectedEntries = getSelectedEntries(); bool permanent = !m_db->metadata()->recycleBinEnabled(); if (GuiTools::confirmDeleteEntries(this, selectedEntries, permanent)) { GuiTools::deleteEntriesResolveReferences(this, selectedEntries, permanent); diff --git a/src/gui/reports/ReportsWidgetHibp.h b/src/gui/reports/ReportsWidgetHibp.h index 2955358ad..8e0d5e47b 100644 --- a/src/gui/reports/ReportsWidgetHibp.h +++ b/src/gui/reports/ReportsWidgetHibp.h @@ -24,7 +24,7 @@ #include #ifdef WITH_XC_NETWORKING -#include "core/HibpDownloader.h" +#include "networking/HibpDownloader.h" #endif class Database; @@ -43,7 +43,7 @@ class ReportsWidgetHibp : public QWidget Q_OBJECT public: explicit ReportsWidgetHibp(QWidget* parent = nullptr); - ~ReportsWidgetHibp(); + ~ReportsWidgetHibp() override; void loadSettings(QSharedPointer db); void saveSettings(); @@ -58,6 +58,8 @@ public slots: void fetchFailed(const QString& error); void makeHibpTable(); void customMenuRequested(QPoint); + QList getSelectedEntries(); + void expireSelectedEntries(); void deleteSelectedEntries(); private: diff --git a/src/gui/reports/ReportsWidgetPasskeys.cpp b/src/gui/reports/ReportsWidgetPasskeys.cpp index 696fcd832..831f4c721 100644 --- a/src/gui/reports/ReportsWidgetPasskeys.cpp +++ b/src/gui/reports/ReportsWidgetPasskeys.cpp @@ -19,7 +19,9 @@ #include "ui_ReportsWidgetPasskeys.h" #include "browser/BrowserPasskeys.h" +#include "browser/PasskeyUtils.h" #include "core/AsyncTask.h" +#include "core/EntryAttributes.h" #include "core/Group.h" #include "core/Metadata.h" #include "gui/GuiTools.h" @@ -74,7 +76,7 @@ PasskeyList::PasskeyList(const QSharedPointer& db) } for (auto entry : group->entries()) { - if (entry->isRecycled() || !entry->attributes()->hasKey(BrowserPasskeys::KPEX_PASSKEY_PRIVATE_KEY_PEM)) { + if (entry->isRecycled() || !entry->attributes()->hasKey(EntryAttributes::KPEX_PASSKEY_PRIVATE_KEY_PEM)) { continue; } @@ -132,8 +134,8 @@ void ReportsWidgetPasskeys::addPasskeyRow(Group* group, Entry* entry) auto row = QList(); row << new QStandardItem(Icons::entryIconPixmap(entry), title); row << new QStandardItem(Icons::groupIconPixmap(group), group->hierarchy().join("/")); - row << new QStandardItem(entry->username()); - row << new QStandardItem(entry->attributes()->value(BrowserPasskeys::KPEX_PASSKEY_RELYING_PARTY)); + row << new QStandardItem(passkeyUtils()->getUsernameFromEntry(entry)); + row << new QStandardItem(entry->attributes()->value(EntryAttributes::KPEX_PASSKEY_RELYING_PARTY)); row << new QStandardItem(urlList.join('\n')); // Set tooltips diff --git a/src/gui/reports/ReportsWidgetStatistics.cpp b/src/gui/reports/ReportsWidgetStatistics.cpp index 280ed4de5..2f1759cd7 100644 --- a/src/gui/reports/ReportsWidgetStatistics.cpp +++ b/src/gui/reports/ReportsWidgetStatistics.cpp @@ -19,6 +19,7 @@ #include "ui_ReportsWidgetStatistics.h" #include "core/AsyncTask.h" +#include "core/Clock.h" #include "core/DatabaseStats.h" #include "core/Group.h" #include "core/Metadata.h" @@ -41,9 +42,7 @@ ReportsWidgetStatistics::ReportsWidgetStatistics(QWidget* parent) m_ui->statisticsTableView->horizontalHeader()->setSectionResizeMode(QHeaderView::ResizeToContents); } -ReportsWidgetStatistics::~ReportsWidgetStatistics() -{ -} +ReportsWidgetStatistics::~ReportsWidgetStatistics() = default; void ReportsWidgetStatistics::addStatsRow(QString name, QString value, bool bad, QString badMsg) { @@ -88,9 +87,8 @@ void ReportsWidgetStatistics::calculateStats() addStatsRow(tr("Database name"), m_db->metadata()->name()); addStatsRow(tr("Description"), m_db->metadata()->description()); addStatsRow(tr("Location"), m_db->filePath()); - addStatsRow(tr("Database created"), - m_db->rootGroup()->timeInfo().creationTime().toString(Qt::DefaultLocaleShortDate)); - addStatsRow(tr("Last saved"), stats->modified.toString(Qt::DefaultLocaleShortDate)); + addStatsRow(tr("Database created"), Clock::toString(m_db->rootGroup()->timeInfo().creationTime())); + addStatsRow(tr("Last saved"), Clock::toString(stats->modified)); addStatsRow(tr("Unsaved changes"), m_db->isModified() ? tr("yes") : tr("no"), m_db->isModified(), diff --git a/src/gui/reports/ReportsWidgetStatistics.h b/src/gui/reports/ReportsWidgetStatistics.h index cc11a75f5..02931891c 100644 --- a/src/gui/reports/ReportsWidgetStatistics.h +++ b/src/gui/reports/ReportsWidgetStatistics.h @@ -34,7 +34,7 @@ class ReportsWidgetStatistics : public QWidget Q_OBJECT public: explicit ReportsWidgetStatistics(QWidget* parent = nullptr); - ~ReportsWidgetStatistics(); + ~ReportsWidgetStatistics() override; void loadSettings(QSharedPointer db); void saveSettings(); diff --git a/src/gui/styles/base/BaseStyle.cpp b/src/gui/styles/base/BaseStyle.cpp index 60df4a2ee..8fa8f64bb 100644 --- a/src/gui/styles/base/BaseStyle.cpp +++ b/src/gui/styles/base/BaseStyle.cpp @@ -41,10 +41,8 @@ #ifdef Q_OS_MACOS #include -#if QT_VERSION >= QT_VERSION_CHECK(5, 9, 0) #include #endif -#endif #include "gui/Icons.h" @@ -52,15 +50,6 @@ QT_BEGIN_NAMESPACE Q_GUI_EXPORT int qt_defaultDpiX(); QT_END_NAMESPACE -// Redefine Q_FALLTHROUGH for older Qt versions -#ifndef Q_FALLTHROUGH -#if (defined(Q_CC_GNU) && Q_CC_GNU >= 700) && !defined(Q_CC_INTEL) -#define Q_FALLTHROUGH() __attribute__((fallthrough)) -#else -#define Q_FALLTHROUGH() (void)0 -#endif -#endif - namespace Phantom { namespace @@ -593,7 +582,7 @@ namespace Phantom } else { // Remove the oldest guy from the cache. Remember that because we may // re-enter QStyle functions multiple times when drawing or calculating - // something, we may have to load several swaitches derived from + // something, we may have to load several switches derived from // different QPalettes on different stack frames at the same time. But as // an extra cost-savings measure, we'll check and see if something else // has a reference to the removed guy. If there aren't any references to @@ -773,9 +762,7 @@ namespace Phantom static MenuItemMetrics ofFontHeight(int fontHeight); private: - MenuItemMetrics() - { - } + MenuItemMetrics() = default; }; MenuItemMetrics MenuItemMetrics::ofFontHeight(int fontHeight) @@ -788,7 +775,7 @@ namespace Phantom m.rightMarginForArrow = static_cast(fontHeight * MenuItem_RightMarginForArrowFontRatio); m.topMargin = static_cast(fontHeight * MenuItem_VerticalMarginsFontRatio); m.bottomMargin = static_cast(fontHeight * MenuItem_VerticalMarginsFontRatio); - int checkVMargin = static_cast(fontHeight * MenuItem_CheckMarkVerticalInsetFontRatio); + auto checkVMargin = static_cast(fontHeight * MenuItem_CheckMarkVerticalInsetFontRatio); int checkHeight = fontHeight - checkVMargin * 2; if (checkHeight < 0) checkHeight = 0; @@ -817,7 +804,7 @@ namespace Phantom menuItemCheckRect(const MenuItemMetrics& metrics, Qt::LayoutDirection direction, QRect itemRect, bool hasArrow) { QRect r = menuItemContentRect(metrics, itemRect, hasArrow); - int checkVMargin = static_cast(metrics.fontHeight * MenuItem_CheckMarkVerticalInsetFontRatio); + auto checkVMargin = static_cast(metrics.fontHeight * MenuItem_CheckMarkVerticalInsetFontRatio); if (checkVMargin < 0) checkVMargin = 0; r.setSize(QSize(metrics.checkWidth, metrics.fontHeight)); @@ -1035,15 +1022,6 @@ namespace Phantom painter->restore(); } - int fontMetricsWidth(const QFontMetrics& fontMetrics, const QString& text) - { -#if QT_VERSION < QT_VERSION_CHECK(5, 11, 0) - return fontMetrics.width(text, text.size(), Qt::TextBypassShaping); -#else - return fontMetrics.horizontalAdvance(text); -#endif - } - // This always draws the arrow with the correct aspect ratio, even if the // provided bounding rect is non-square. The base edge of the triangle is // snapped to a whole pixel to avoid anti-aliasing making it look soft. @@ -1051,7 +1029,7 @@ namespace Phantom // Expected time (release): 5usecs for regular-sized arrows Q_NEVER_INLINE void drawArrow(QPainter* p, QRect rect, Qt::ArrowType arrowDirection, const QBrush& brush) { - const qreal ArrowBaseRatio = 0.9; + const qreal ArrowBaseRatio = 1.0; qreal irx, iry, irw, irh; QRectF(rect).getRect(&irx, &iry, &irw, &irh); if (irw < 1.0 || irh < 1.0) @@ -1156,11 +1134,11 @@ namespace Phantom points[0] = QPointF(0.0, 0.55); points[1] = QPointF(0.4, 1.0); points[2] = QPointF(1.0, 0); - for (int i = 0; i < 3; ++i) { - QPointF pnt = points[i]; + for (auto& point : points) { + QPointF pnt = point; pnt.setX(pnt.x() * dimx + x); pnt.setY(pnt.y() * dimy + y); - points[i] = pnt; + point = pnt; } scratchPen.setBrush(swatch.brush(color)); scratchPen.setCapStyle(Qt::RoundCap); @@ -1478,13 +1456,13 @@ void BaseStyle::drawPrimitive(PrimitiveElement elem, } case PE_FrameDockWidget: { painter->save(); - QColor softshadow = option->palette.background().color().darker(120); + QColor softshadow = option->palette.window().color().darker(120); QRect r = option->rect; painter->setPen(softshadow); painter->drawRect(r.adjusted(0, 0, -1, -1)); painter->setPen(QPen(option->palette.light(), 1)); painter->drawLine(QPoint(r.left() + 1, r.top() + 1), QPoint(r.left() + 1, r.bottom() - 1)); - painter->setPen(QPen(option->palette.background().color().darker(120))); + painter->setPen(QPen(option->palette.window().color().darker(120))); painter->drawLine(QPoint(r.left() + 1, r.bottom() - 1), QPoint(r.right() - 2, r.bottom() - 1)); painter->drawLine(QPoint(r.right() - 1, r.top() + 1), QPoint(r.right() - 1, r.bottom() - 1)); painter->restore(); @@ -1671,7 +1649,7 @@ void BaseStyle::drawPrimitive(PrimitiveElement elem, if (arrow == Qt::DownArrow && !qstyleoption_cast(option) && widget) { auto tbutton = qobject_cast(widget); if (tbutton && tbutton->popupMode() != QToolButton::InstantPopup && tbutton->defaultAction()) { - int dim = static_cast(qMin(rw, rh) * 0.25); + auto dim = static_cast(qMin(rw, rh) * 0.25); aw -= dim; ah -= dim; // We have another hack in PE_IndicatorButtonDropDown where we shift @@ -1736,12 +1714,12 @@ void BaseStyle::drawPrimitive(PrimitiveElement elem, // TODO replace with new code const int margin = 6; const int offset = r.height() / 2; - painter->setPen(QPen(option->palette.background().color().darker(110))); + painter->setPen(QPen(option->palette.window().color().darker(110))); painter->drawLine(r.topLeft().x() + margin, r.topLeft().y() + offset, r.topRight().x() - margin, r.topRight().y() + offset); - painter->setPen(QPen(option->palette.background().color().lighter(110))); + painter->setPen(QPen(option->palette.window().color().lighter(110))); painter->drawLine(r.topLeft().x() + margin, r.topLeft().y() + offset + 1, r.topRight().x() - margin, @@ -2472,7 +2450,7 @@ void BaseStyle::drawControl(ControlElement element, QPixmap pixmap = header->icon.pixmap(window, QSize(iconExtent, iconExtent), (header->state & State_Enabled) ? QIcon::Normal : QIcon::Disabled); - int pixw = static_cast(pixmap.width() / pixmap.devicePixelRatio()); + auto pixw = static_cast(pixmap.width() / pixmap.devicePixelRatio()); QRect aligned = alignedRect( header->direction, QFlag(header->iconAlignment), pixmap.size() / pixmap.devicePixelRatio(), rect); QRect inter = aligned.intersected(rect); @@ -2658,7 +2636,21 @@ void BaseStyle::drawControl(ControlElement element, } break; } + case CE_MenuTearoff: { + if (option->state & State_Selected) { + painter->fillRect(option->rect, option->palette.brush(QPalette::Highlight)); + painter->setPen(QPen(option->palette.highlightedText().color(), 1, Qt::DashLine)); + } else { + painter->fillRect(option->rect, option->palette.brush(QPalette::Button)); + painter->setPen(QPen(option->palette.buttonText().color(), 1, Qt::DashLine)); + } + painter->drawLine(option->rect.x() + 2, + option->rect.y() + option->rect.height() / 2, + option->rect.x() + option->rect.width() - 4, + option->rect.y() + option->rect.height() / 2); + break; + } case CE_MenuItem: { auto menuItem = qstyleoption_cast(option); if (!menuItem) @@ -2745,8 +2737,8 @@ void BaseStyle::drawControl(ControlElement element, } QWindow* window = widget ? widget->windowHandle() : nullptr; QPixmap pixmap = menuItem->icon.pixmap(window, iconSize, mode, state); - const int pixw = static_cast(pixmap.width() / pixmap.devicePixelRatio()); - const int pixh = static_cast(pixmap.height() / pixmap.devicePixelRatio()); + const auto pixw = static_cast(pixmap.width() / pixmap.devicePixelRatio()); + const auto pixh = static_cast(pixmap.height() / pixmap.devicePixelRatio()); QRect pixmapRect = QStyle::alignedRect(option->direction, Qt::AlignCenter, QSize(pixw, pixh), iconRect); painter->drawPixmap(pixmapRect.topLeft(), pixmap); } @@ -2772,7 +2764,7 @@ void BaseStyle::drawControl(ControlElement element, // that when it is resolved against the device, this font will win. This // is mainly to handle cases where someone sets the font on the window // and then the combo inherits it and passes it onward. At that point the - // resolve mask is very, very weak. This makes it stonger. + // resolve mask is very, very weak. This makes it stronger. #if 0 QFont font = menuItem->font; font.setPointSizeF(QFontInfo(menuItem->font).pointSizeF()); @@ -2883,8 +2875,8 @@ void BaseStyle::drawControl(ControlElement element, QIcon::State state = button->state & State_On ? QIcon::On : QIcon::Off; auto window = widget ? widget->window()->windowHandle() : nullptr; QPixmap pixmap = button->icon.pixmap(window, button->iconSize, mode, state); - int pixmapWidth = static_cast(pixmap.width() / pixmap.devicePixelRatio()); - int pixmapHeight = static_cast(pixmap.height() / pixmap.devicePixelRatio()); + auto pixmapWidth = static_cast(pixmap.width() / pixmap.devicePixelRatio()); + auto pixmapHeight = static_cast(pixmap.height() / pixmap.devicePixelRatio()); int labelWidth = pixmapWidth; int labelHeight = pixmapHeight; // 4 is hardcoded in QPushButton::sizeHint() @@ -3270,13 +3262,13 @@ void BaseStyle::drawComplexControl(ComplexControl control, QColor outline = option->palette.dark().color(); QColor titleBarFrameBorder(active ? highlight.darker(180) : outline.darker(110)); - QColor titleBarHighlight(active ? highlight.lighter(120) : palette.background().color().lighter(120)); + QColor titleBarHighlight(active ? highlight.lighter(120) : palette.window().color().lighter(120)); QColor textColor(active ? 0xffffff : 0xff000000); QColor textAlphaColor(active ? 0xffffff : 0xff000000); { // Fill title - QColor titlebarColor = QColor(active ? highlight : palette.background().color()); + auto titlebarColor = QColor(active ? highlight : palette.window().color()); painter->fillRect(option->rect.adjusted(1, 1, -1, 0), titlebarColor); // Frame and rounded corners painter->setPen(titleBarFrameBorder); @@ -3888,11 +3880,9 @@ int BaseStyle::pixelMetric(PixelMetric metric, const QStyleOption* option, const case PM_DockWidgetTitleBarButtonMargin: val = 2; break; -#if (QT_VERSION >= QT_VERSION_CHECK(5, 8, 0)) case PM_TitleBarButtonSize: val = 19; break; -#endif case PM_MaximumDragDistance: return -1; // Do not dpi-scale because the value is magic case PM_TabCloseIndicatorWidth: @@ -3979,14 +3969,14 @@ QSize BaseStyle::sizeFromContents(ContentsType type, if (!btn->icon.isNull() || !btn->text.isEmpty()) margins = proxy()->pixelMetric(isRadio ? PM_RadioButtonLabelSpacing : PM_CheckBoxLabelSpacing, option, widget); - return QSize(size.width() + w + margins, qMax(size.height(), h)); + return {size.width() + w + margins, qMax(size.height(), h)}; } case CT_MenuBarItem: { int fontHeight = option ? option->fontMetrics.height() : size.height(); - int w = static_cast(fontHeight * Ph::MenuBar_HorizontalPaddingFontRatio); - int h = static_cast(fontHeight * Ph::MenuBar_VerticalPaddingFontRatio); + auto w = static_cast(fontHeight * Ph::MenuBar_HorizontalPaddingFontRatio); + auto h = static_cast(fontHeight * Ph::MenuBar_VerticalPaddingFontRatio); int line = Ph::dpiScaled(1); - return QSize(size.width() + w * 2, size.height() + h * 2 + line); + return {size.width() + w * 2, size.height() + h * 2 + line}; } case CT_MenuItem: { auto menuItem = qstyleoption_cast(option); @@ -4113,7 +4103,7 @@ QSize BaseStyle::sizeFromContents(ContentsType type, xadd += 2; yadd += 2; } - return QSize(size.width() + xadd, size.height() + yadd); + return {size.width() + xadd, size.height() + yadd}; } case CT_ItemViewItem: { auto vopt = qstyleoption_cast(option); @@ -4176,7 +4166,8 @@ QSize BaseStyle::sizeFromContents(ContentsType type, auto pbopt = qstyleoption_cast(option); if (!pbopt || pbopt->text.isEmpty()) break; - int hpad = static_cast(pbopt->fontMetrics.height() * Phantom::PushButton_HorizontalPaddingFontHeightRatio); + auto hpad = + static_cast(pbopt->fontMetrics.height() * Phantom::PushButton_HorizontalPaddingFontHeightRatio); newSize.rwidth() += hpad * 2; if (widget && qobject_cast(widget->parent())) { int dialogButtonMinWidth = Phantom::dpiScaled(80); @@ -4334,7 +4325,7 @@ QRect BaseStyle::subControlRect(ComplexControl control, break; case SC_SpinBoxDown: if (spinbox->buttonSymbols == QAbstractSpinBox::NoButtons) - return QRect(); + return {}; rect = QRect(x, center, buttonWidth, spinbox->rect.bottom() - center - fw + 1); break; @@ -4382,7 +4373,7 @@ QRect BaseStyle::subControlRect(ComplexControl control, int textHeight = option->fontMetrics.height(); // width()/horizontalAdvance() is faster than size() and good enough for // us, since we only support a single line of text here anyway. - int textWidth = Phantom::fontMetricsWidth(option->fontMetrics, groupBox->text); + int textWidth = option->fontMetrics.horizontalAdvance(groupBox->text); int indicatorWidth = proxy()->pixelMetric(PM_IndicatorWidth, option, widget); int indicatorHeight = proxy()->pixelMetric(PM_IndicatorHeight, option, widget); int margin = 0; @@ -4428,13 +4419,13 @@ QRect BaseStyle::subControlRect(ComplexControl control, case CC_ComboBox: { auto cb = qstyleoption_cast(option); if (!cb) - return QRect(); + return {}; int frame = cb->frame ? proxy()->pixelMetric(PM_ComboBoxFrameWidth, cb, widget) : 0; QRect r = option->rect; r.adjust(frame, frame, -frame, -frame); int dim = qMin(r.width(), r.height()); if (dim < 1) - return QRect(); + return {}; switch (subControl) { case SC_ComboBoxFrame: return cb->rect; @@ -4625,10 +4616,8 @@ int BaseStyle::styleHint(StyleHint hint, return Phantom::ShowItemViewDecorationSelected; case SH_ItemView_MovementWithoutUpdatingSelection: return 1; -#if (QT_VERSION >= QT_VERSION_CHECK(5, 7, 0)) case SH_ItemView_ScrollMode: return QAbstractItemView::ScrollPerPixel; -#endif case SH_ScrollBar_ContextMenu: #ifdef Q_OS_MAC return 0; diff --git a/src/gui/styles/base/basestyle.qss b/src/gui/styles/base/basestyle.qss index ee0fa4e02..d5211e90a 100644 --- a/src/gui/styles/base/basestyle.qss +++ b/src/gui/styles/base/basestyle.qss @@ -21,7 +21,9 @@ QCheckBox, QRadioButton { spacing: 10px; } -ReportsDialog QTableView::item { +ReportsDialog QTableView::item, +EntryAttachmentsWidget QTableView::item +{ padding: 4px; } @@ -30,15 +32,14 @@ DatabaseWidget, DatabaseWidget #groupView, DatabaseWidget #tagView { border: none; } -EntryPreviewWidget QLineEdit, EntryPreviewWidget QTextEdit, -EntryPreviewWidget TagsEdit +EntryPreviewWidget *[blendIn="true"] { background-color: palette(window); border: none; padding-left: 0px; } -DatabaseOpenWidget #centralStack { +DatabaseOpenWidget #centralStack, DatabaseOpenWidget #publicSummaryLabel { border: 1px solid palette(mid); background: palette(light); } @@ -71,10 +72,6 @@ QPlainTextEdit, QTextEdit { padding-left: 4px; } -QStatusBar { - background-color: palette(window); -} - *[title="true"] { font-weight: bold; } diff --git a/src/gui/styles/base/classicstyle.qss b/src/gui/styles/base/classicstyle.qss index d0ab2b88f..72308f39e 100644 --- a/src/gui/styles/base/classicstyle.qss +++ b/src/gui/styles/base/classicstyle.qss @@ -1,4 +1,4 @@ -DatabaseOpenWidget #centralStack { +DatabaseOpenWidget #centralStack, DatabaseOpenWidget #publicSummaryLabel { border: 2px groove palette(mid); background: palette(light); } diff --git a/src/gui/styles/base/phantomcolor.cpp b/src/gui/styles/base/phantomcolor.cpp index a11ab3c92..a53da3a46 100644 --- a/src/gui/styles/base/phantomcolor.cpp +++ b/src/gui/styles/base/phantomcolor.cpp @@ -27,8 +27,8 @@ */ #include "phantomcolor.h" +#include #include -#include namespace Phantom { @@ -398,9 +398,9 @@ namespace Phantom QColor qcolor_of_rgb(qreal r, qreal g, qreal b) { - int r_ = static_cast(std::lround(srgb_of_linear(r) * 255.0)); - int g_ = static_cast(std::lround(srgb_of_linear(g) * 255.0)); - int b_ = static_cast(std::lround(srgb_of_linear(b) * 255.0)); + auto r_ = static_cast(std::lround(srgb_of_linear(r) * 255.0)); + auto g_ = static_cast(std::lround(srgb_of_linear(g) * 255.0)); + auto b_ = static_cast(std::lround(srgb_of_linear(b) * 255.0)); return {r_, g_, b_}; } diff --git a/src/gui/styles/base/phantomcolor.h b/src/gui/styles/base/phantomcolor.h index f9573ba65..8eed357ab 100644 --- a/src/gui/styles/base/phantomcolor.h +++ b/src/gui/styles/base/phantomcolor.h @@ -42,9 +42,7 @@ namespace Phantom struct Rgb { qreal r, g, b; - Rgb() - { - } + Rgb() = default; Rgb(qreal r, qreal g, qreal b) : r(r) , g(g) @@ -78,9 +76,7 @@ namespace Phantom struct Hsl { qreal h, s, l; - Hsl() - { - } + Hsl() = default; Hsl(qreal h, qreal s, qreal l) : h(h) , s(s) @@ -113,7 +109,7 @@ namespace Phantom return (1.0 - a) * x + a * y; } - // Linearly interpolate two QColors after trasnforming them to linear color + // Linearly interpolate two QColors after transforming them to linear color // space, treating the QColor values as if they were in sRGB space. The // returned QColor is converted back to sRGB space. QColor lerpQColor(const QColor& x, const QColor& y, qreal a); diff --git a/src/gui/styles/dark/DarkStyle.cpp b/src/gui/styles/dark/DarkStyle.cpp index 3c4731b2d..daf16aaac 100644 --- a/src/gui/styles/dark/DarkStyle.cpp +++ b/src/gui/styles/dark/DarkStyle.cpp @@ -51,11 +51,9 @@ QPalette DarkStyle::standardPalette() const palette.setColor(QPalette::Inactive, QPalette::Text, QRgb(0xC8C8C6)); palette.setColor(QPalette::Disabled, QPalette::Text, QRgb(0x707070)); -#if (QT_VERSION >= QT_VERSION_CHECK(5, 12, 0)) palette.setColor(QPalette::Active, QPalette::PlaceholderText, QRgb(0x7D7D82)); palette.setColor(QPalette::Inactive, QPalette::PlaceholderText, QRgb(0x87888C)); palette.setColor(QPalette::Disabled, QPalette::PlaceholderText, QRgb(0x737373)); -#endif palette.setColor(QPalette::Active, QPalette::BrightText, QRgb(0x252627)); palette.setColor(QPalette::Inactive, QPalette::BrightText, QRgb(0x2D2D2F)); @@ -115,7 +113,7 @@ QString DarkStyle::getAppStyleSheet() const void DarkStyle::polish(QWidget* widget) { if (qobject_cast(widget) || qobject_cast(widget) || qobject_cast(widget) - || qobject_cast(widget) || qobject_cast(widget)) { + || qobject_cast(widget)) { auto palette = widget->palette(); #if defined(Q_OS_MACOS) if (!osUtils->isDarkMode()) { diff --git a/src/gui/styles/dark/darkstyle.qss b/src/gui/styles/dark/darkstyle.qss index 23bcfd927..716430113 100644 --- a/src/gui/styles/dark/darkstyle.qss +++ b/src/gui/styles/dark/darkstyle.qss @@ -1,15 +1,24 @@ -DatabaseWidget:!active, GroupView:!active, -EntryPreviewWidget QLineEdit:!active, EntryPreviewWidget QTextEdit:!active, -EntryPreviewWidget TagsEdit:!active { +DatabaseWidget:!active, +DatabaseWidget #groupView:!active, DatabaseWidget #tagView:!active, +EntryPreviewWidget *:!active[blendIn="true"] { background-color: #404042; } -DatabaseWidget:disabled, GroupView:disabled, -EntryPreviewWidget QLineEdit:disabled, EntryPreviewWidget QTextEdit:disabled, -EntryPreviewWidget TagsEdit:disabled { +DatabaseWidget:disabled, +DatabaseWidget #groupView:disabled, DatabaseWidget #tagView:disabled, +EntryPreviewWidget *:disabled[blendIn="true"] { background-color: #424242; } +QMenu { + border: 1px solid #56565A; +} + +QMenu::separator { + height: 1px; + background-color: #56565A; +} + QPushButton:!default:hover { /* Using slightly darker shade from palette(button) */ background: #252528; @@ -20,6 +29,10 @@ QPushButton:default:hover, QPushButton:checked:hover { background: #2E582E; } +QSplitterHandle { + background-color: #56565A; +} + QToolTip { color: #BFBFBF; background-color: #2D532D; diff --git a/src/gui/styles/light/LightStyle.cpp b/src/gui/styles/light/LightStyle.cpp index 93cfeb632..f73995412 100644 --- a/src/gui/styles/light/LightStyle.cpp +++ b/src/gui/styles/light/LightStyle.cpp @@ -51,11 +51,9 @@ QPalette LightStyle::standardPalette() const palette.setColor(QPalette::Inactive, QPalette::Text, QRgb(0x252528)); palette.setColor(QPalette::Disabled, QPalette::Text, QRgb(0x8C8C92)); -#if (QT_VERSION >= QT_VERSION_CHECK(5, 12, 0)) palette.setColor(QPalette::Active, QPalette::PlaceholderText, QRgb(0x71727D)); palette.setColor(QPalette::Inactive, QPalette::PlaceholderText, QRgb(0x878893)); palette.setColor(QPalette::Disabled, QPalette::PlaceholderText, QRgb(0xA3A4AC)); -#endif palette.setColor(QPalette::Active, QPalette::BrightText, QRgb(0xF3F3F4)); palette.setColor(QPalette::Inactive, QPalette::BrightText, QRgb(0xEAEAEB)); @@ -115,7 +113,7 @@ QString LightStyle::getAppStyleSheet() const void LightStyle::polish(QWidget* widget) { if (qobject_cast(widget) || qobject_cast(widget) || qobject_cast(widget) - || qobject_cast(widget) || qobject_cast(widget)) { + || qobject_cast(widget)) { auto palette = widget->palette(); #if defined(Q_OS_MACOS) if (osUtils->isDarkMode()) { diff --git a/src/gui/styles/light/lightstyle.qss b/src/gui/styles/light/lightstyle.qss index 2764a56b0..123267c30 100644 --- a/src/gui/styles/light/lightstyle.qss +++ b/src/gui/styles/light/lightstyle.qss @@ -1,12 +1,12 @@ -DatabaseWidget:!active, GroupView:!active, -EntryPreviewWidget QLineEdit:!active, EntryPreviewWidget QTextEdit:!active, -EntryPreviewWidget TagsEdit:!active { +DatabaseWidget:!active, +DatabaseWidget #groupView:!active, DatabaseWidget #tagView:!active, +EntryPreviewWidget *:!active[blendIn="true"] { background-color: #FCFCFC; } -DatabaseWidget:disabled, GroupView:disabled, -EntryPreviewWidget QLineEdit:disabled, EntryPreviewWidget QTextEdit:disabled, -EntryPreviewWidget TagsEdit:disabled { +DatabaseWidget:disabled, +DatabaseWidget #groupView:disabled, DatabaseWidget #tagView:disabled, +EntryPreviewWidget *:disabled[blendIn="true"] { background-color: #EDEDED; } diff --git a/src/gui/tag/TagModel.cpp b/src/gui/tag/TagModel.cpp index 99f253270..a19f263d8 100644 --- a/src/gui/tag/TagModel.cpp +++ b/src/gui/tag/TagModel.cpp @@ -30,12 +30,11 @@ TagModel::TagModel(QObject* parent) { m_defaultSearches << qMakePair(tr("Clear Search"), QString("")) << qMakePair(tr("All Entries"), QString("*")) << qMakePair(tr("Expired"), QString("is:expired")) - << qMakePair(tr("Weak Passwords"), QString("is:weak")); + << qMakePair(tr("Weak Passwords"), QString("is:weak")) + << qMakePair(tr("TOTP Entries"), QString("has:totp")); } -TagModel::~TagModel() -{ -} +TagModel::~TagModel() = default; void TagModel::setDatabase(QSharedPointer db) { diff --git a/src/gui/tag/TagView.cpp b/src/gui/tag/TagView.cpp index 8afdac44a..033061292 100644 --- a/src/gui/tag/TagView.cpp +++ b/src/gui/tag/TagView.cpp @@ -20,6 +20,7 @@ #include "TagModel.h" #include "core/Database.h" #include "core/Metadata.h" +#include "gui/Application.h" #include "gui/Icons.h" #include "gui/MessageBox.h" @@ -39,7 +40,11 @@ public: if (index.data(Qt::UserRole + 1).toBool()) { QRect bounds = option.rect; bounds.setY(bounds.bottom()); - painter->fillRect(bounds, option.palette.mid()); + if (kpxcApp->isDarkTheme()) { + painter->fillRect(bounds, option.palette.mid().color().lighter(185)); + } else { + painter->fillRect(bounds, option.palette.mid()); + } } } }; diff --git a/src/gui/tag/TagsEdit.cpp b/src/gui/tag/TagsEdit.cpp index 4388f4790..1d6bcfa73 100644 --- a/src/gui/tag/TagsEdit.cpp +++ b/src/gui/tag/TagsEdit.cpp @@ -39,12 +39,6 @@ #include -#if QT_VERSION < QT_VERSION_CHECK(5, 11, 0) -#define FONT_METRICS_WIDTH(fmt, ...) fmt.width(__VA_ARGS__) -#else -#define FONT_METRICS_WIDTH(fmt, ...) fmt.horizontalAdvance(__VA_ARGS__) -#endif - namespace { @@ -239,11 +233,11 @@ struct TagsEdit::Impl auto const e = std::end(tags); if (cursorVisible()) { auto const m = b + static_cast(editing_index); - calcRects(lt, row, r, fm, std::make_pair(b, m)); + calcRects(lt, row, r, fm, std::pair(b, m)); calcEditorRect(lt, row, r, fm, m); - calcRects(lt, row, r, fm, std::make_pair(m + 1, e)); + calcRects(lt, row, r, fm, std::pair(m + 1, e)); } else { - calcRects(lt, row, r, fm, std::make_pair(b, e)); + calcRects(lt, row, r, fm, std::pair(b, e)); } r.setBottom(lt.y() + fm.height() + fm.leading() + tag_inner.top() + tag_inner.bottom() - 1); @@ -255,7 +249,7 @@ struct TagsEdit::Impl { for (auto it = range.first; it != range.second; ++it) { // calc text rect - const auto text_w = FONT_METRICS_WIDTH(fm, it->text); + const auto text_w = fm.horizontalAdvance(it->text); auto const text_h = fm.height() + fm.leading(); auto const w = cross_deleter ? tag_inner.left() + tag_inner.right() + tag_cross_padding * 2 + tag_cross_width @@ -280,7 +274,7 @@ struct TagsEdit::Impl template void calcEditorRect(QPoint& lt, size_t& row, QRect r, QFontMetrics const& fm, It it) const { - auto const text_w = FONT_METRICS_WIDTH(fm, text_layout.text()); + auto const text_w = fm.horizontalAdvance(text_layout.text()); auto const text_h = fm.height() + fm.leading(); auto const w = tag_inner.left() + tag_inner.right(); auto const h = tag_inner.top() + tag_inner.bottom(); @@ -343,7 +337,7 @@ struct TagsEdit::Impl assert(i < tags.size()); auto occurrencesOfCurrentText = std::count_if(tags.cbegin(), tags.cend(), [this](const auto& tag) { return tag.text == currentText(); }); - if (currentText().isEmpty() || occurrencesOfCurrentText > 1) { + if (tags.size() > 1 && (currentText().isEmpty() || occurrencesOfCurrentText > 1)) { tags.erase(std::next(tags.begin(), std::ptrdiff_t(editing_index))); if (editing_index <= i) { // Do we shift positions after `i`? --i; @@ -414,6 +408,7 @@ struct TagsEdit::Impl void setupCompleter() { completer->setWidget(ifce); + completer->setCaseSensitivity(Qt::CaseInsensitive); connect(completer.get(), static_cast(&QCompleter::activated), [this](QString const& text) { currentText(text); }); @@ -668,8 +663,7 @@ void TagsEdit::paintEvent(QPaintEvent*) // tags impl->drawTags( - p, - std::make_pair(impl->tags.cbegin(), std::next(impl->tags.cbegin(), std::ptrdiff_t(impl->editing_index)))); + p, std::pair(impl->tags.cbegin(), std::next(impl->tags.cbegin(), std::ptrdiff_t(impl->editing_index)))); // draw not terminated tag auto const formatting = impl->formatting(); @@ -684,12 +678,10 @@ void TagsEdit::paintEvent(QPaintEvent*) // tags impl->drawTags( - p, - std::make_pair(std::next(impl->tags.cbegin(), std::ptrdiff_t(impl->editing_index + 1)), impl->tags.cend())); + p, std::pair(std::next(impl->tags.cbegin(), std::ptrdiff_t(impl->editing_index + 1)), impl->tags.cend())); } else { - impl->drawTags(p, - std::make_pair(EmptySkipIterator(impl->tags.begin(), impl->tags.end()), - EmptySkipIterator(impl->tags.end()))); + impl->drawTags( + p, std::pair(EmptySkipIterator(impl->tags.begin(), impl->tags.end()), EmptySkipIterator(impl->tags.end()))); } } diff --git a/src/gui/widgets/ElidedLabel.h b/src/gui/widgets/ElidedLabel.h index 5dd14891d..1f90d056e 100644 --- a/src/gui/widgets/ElidedLabel.h +++ b/src/gui/widgets/ElidedLabel.h @@ -51,7 +51,7 @@ private slots: void updateElidedText(); private: - void resizeEvent(QResizeEvent* event); + void resizeEvent(QResizeEvent* event) override; Qt::TextElideMode m_elideMode; QString m_rawText; diff --git a/src/autotype/ShortcutWidget.cpp b/src/gui/widgets/ShortcutWidget.cpp similarity index 81% rename from src/autotype/ShortcutWidget.cpp rename to src/gui/widgets/ShortcutWidget.cpp index 91b2fda93..4f9c14476 100644 --- a/src/autotype/ShortcutWidget.cpp +++ b/src/gui/widgets/ShortcutWidget.cpp @@ -20,13 +20,8 @@ #include #include -#include "autotype/AutoType.h" - ShortcutWidget::ShortcutWidget(QWidget* parent) : QLineEdit(parent) - , m_key(static_cast(0)) - , m_modifiers(nullptr) - , m_locked(false) { setReadOnly(true); } @@ -41,6 +36,11 @@ Qt::KeyboardModifiers ShortcutWidget::modifiers() const return m_modifiers; } +QKeySequence ShortcutWidget::sequence() const +{ + return (m_key == Qt::Key_unknown) ? QKeySequence() : QKeySequence(m_key | m_modifiers); +} + void ShortcutWidget::setShortcut(Qt::Key key, Qt::KeyboardModifiers modifiers) { m_key = key; @@ -48,22 +48,15 @@ void ShortcutWidget::setShortcut(Qt::Key key, Qt::KeyboardModifiers modifiers) m_locked = true; displayShortcut(m_key, m_modifiers); - - QString error; - if (autoType()->registerGlobalShortcut(m_key, m_modifiers, &error)) { - setStyleSheet(""); - } else { - QToolTip::showText(mapToGlobal(rect().bottomLeft()), error); - setStyleSheet("background-color: #FF9696;"); - } + emit shortcutChanged(m_key, m_modifiers); } void ShortcutWidget::resetShortcut() { - m_key = static_cast(0); - m_modifiers = nullptr; + m_key = Qt::Key_unknown; + m_modifiers = Qt::NoModifier; m_locked = false; - autoType()->unregisterGlobalShortcut(); + emit shortcutReset(); } void ShortcutWidget::keyPressEvent(QKeyEvent* event) @@ -90,7 +83,7 @@ void ShortcutWidget::keyEvent(QKeyEvent* event) return; } - Qt::Key key = static_cast(event->key()); + auto key = static_cast(event->key()); if (key <= 0 || key == Qt::Key_unknown) { return; @@ -116,13 +109,11 @@ void ShortcutWidget::keyEvent(QKeyEvent* event) setShortcut(key, modifiers); } else { resetShortcut(); - setStyleSheet(""); displayShortcut(key, modifiers); } } else { if (m_locked) { resetShortcut(); - setStyleSheet(""); } displayShortcut(static_cast(0), modifiers); diff --git a/src/autotype/ShortcutWidget.h b/src/gui/widgets/ShortcutWidget.h similarity index 82% rename from src/autotype/ShortcutWidget.h rename to src/gui/widgets/ShortcutWidget.h index 60898ab7e..6ff9b3d77 100644 --- a/src/autotype/ShortcutWidget.h +++ b/src/gui/widgets/ShortcutWidget.h @@ -18,6 +18,7 @@ #ifndef KEEPASSX_SHORTCUTWIDGET_H #define KEEPASSX_SHORTCUTWIDGET_H +#include #include class ShortcutWidget : public QLineEdit @@ -26,10 +27,17 @@ class ShortcutWidget : public QLineEdit public: explicit ShortcutWidget(QWidget* parent = nullptr); + Qt::Key key() const; Qt::KeyboardModifiers modifiers() const; + QKeySequence sequence() const; + void setShortcut(Qt::Key key, Qt::KeyboardModifiers modifiers); +signals: + void shortcutChanged(Qt::Key key, Qt::KeyboardModifiers modifiers); + void shortcutReset(); + protected: void keyPressEvent(QKeyEvent* event) override; void keyReleaseEvent(QKeyEvent* event) override; @@ -39,9 +47,9 @@ private: void displayShortcut(Qt::Key key, Qt::KeyboardModifiers modifiers); void resetShortcut(); - Qt::Key m_key; - Qt::KeyboardModifiers m_modifiers; - bool m_locked; + Qt::Key m_key = Qt::Key_unknown; + Qt::KeyboardModifiers m_modifiers = Qt::NoModifier; + bool m_locked = false; }; #endif // KEEPASSX_SHORTCUTWIDGET_H diff --git a/src/gui/wizard/ImportWizard.cpp b/src/gui/wizard/ImportWizard.cpp index 05fdbfe38..ff3769347 100644 --- a/src/gui/wizard/ImportWizard.cpp +++ b/src/gui/wizard/ImportWizard.cpp @@ -69,6 +69,11 @@ bool ImportWizard::validateCurrentPage() return ret; } +ImportWizard::ImportIntoType ImportWizard::importIntoType() +{ + return static_cast(field("ImportIntoType").toInt()); +} + QPair ImportWizard::importInto() { auto list = field("ImportInto").toList(); diff --git a/src/gui/wizard/ImportWizard.h b/src/gui/wizard/ImportWizard.h index b7e9de68d..db27e3d5a 100644 --- a/src/gui/wizard/ImportWizard.h +++ b/src/gui/wizard/ImportWizard.h @@ -19,6 +19,7 @@ #define KEEPASSXC_IMPORTWIZARD_H #include +#include #include class Database; @@ -39,7 +40,6 @@ public: bool validateCurrentPage() override; QSharedPointer database(); - QPair importInto(); enum ImportType { @@ -48,9 +48,21 @@ public: IMPORT_OPVAULT, IMPORT_OPUX, IMPORT_BITWARDEN, - IMPORT_KEEPASS1 + IMPORT_PROTONPASS, + IMPORT_KEEPASS1, + IMPORT_REMOTE, }; + enum ImportIntoType + { + NEW_DATABASE = 1, + EXISTING_DATABASE, + TEMPORARY_DATABASE, + }; + + ImportWizard::ImportIntoType importIntoType(); + QPair importInto(); + private: QSharedPointer m_db; QPointer m_pageSelect; diff --git a/src/gui/wizard/ImportWizardPageReview.cpp b/src/gui/wizard/ImportWizardPageReview.cpp index 2cb56791b..3c894e261 100644 --- a/src/gui/wizard/ImportWizardPageReview.cpp +++ b/src/gui/wizard/ImportWizardPageReview.cpp @@ -24,17 +24,27 @@ #include "format/KeePass1Reader.h" #include "format/OPUXReader.h" #include "format/OpVaultReader.h" +#include "format/ProtonPassReader.h" #include "gui/csvImport/CsvImportWidget.h" #include "gui/wizard/ImportWizard.h" +#include "cli/Utils.h" +#include "keys/FileKey.h" +#include "keys/PasswordKey.h" + #include #include #include #include +#include "gui/remote/RemoteSettings.h" + +struct RemoteParams; + ImportWizardPageReview::ImportWizardPageReview(QWidget* parent) : QWizardPage(parent) , m_ui(new Ui::ImportWizardPageReview) + , m_remoteHandler(new RemoteHandler(this)) { } @@ -66,28 +76,35 @@ void ImportWizardPageReview::initializePage() break; case ImportWizard::IMPORT_OPVAULT: m_db = importOPVault(filename, field("ImportPassword").toString()); - setupDatabasePreview(); break; case ImportWizard::IMPORT_OPUX: m_db = importOPUX(filename); - setupDatabasePreview(); break; case ImportWizard::IMPORT_KEEPASS1: m_db = importKeePass1(filename, field("ImportPassword").toString(), field("ImportKeyFile").toString()); - setupDatabasePreview(); break; case ImportWizard::IMPORT_BITWARDEN: m_db = importBitwarden(filename, field("ImportPassword").toString()); - setupDatabasePreview(); + break; + case ImportWizard::IMPORT_PROTONPASS: + m_db = importProtonPass(filename); + break; + case ImportWizard::IMPORT_REMOTE: + m_db = importRemote(field("DownloadCommand").toString(), + field("DownloadInput").toString(), + field("ImportPassword").toString(), + field("ImportKeyFile").toString()); break; default: break; } + + setupDatabasePreview(); } bool ImportWizardPageReview::validatePage() { - if (m_csvWidget && field("ImportType").toInt() == ImportWizard::IMPORT_CSV) { + if (isCsvImport()) { m_db = m_csvWidget->buildDatabase(); } return !m_db.isNull(); @@ -105,18 +122,26 @@ void ImportWizardPageReview::setupCsvImport(const QString& filename) m_csvWidget = new CsvImportWidget(); connect(m_csvWidget, &CsvImportWidget::message, m_ui->messageWidget, [this](QString message) { - m_ui->messageWidget->showMessage(message, KMessageWidget::Error, -1); + if (message.isEmpty()) { + m_ui->messageWidget->hideMessage(); + } else { + m_ui->messageWidget->showMessage(message, MessageWidget::Error, -1); + } }); m_csvWidget->load(filename); - - // Qt does not automatically resize a QScrollWidget in a QWizard... - m_ui->scrollAreaContents->layout()->addWidget(m_csvWidget); - m_ui->scrollArea->setMinimumSize(m_csvWidget->width() + 50, m_csvWidget->height() + 100); } void ImportWizardPageReview::setupDatabasePreview() { + // CSV preview is handled by the import widget + if (isCsvImport()) { + // Qt does not automatically resize a QScrollWidget in a QWizard... + m_ui->scrollAreaContents->layout()->addWidget(m_csvWidget); + m_ui->scrollArea->setMinimumSize(m_csvWidget->width() + 50, m_csvWidget->height() + 100); + return; + } + if (!m_db) { m_ui->scrollArea->setVisible(false); return; @@ -200,3 +225,58 @@ ImportWizardPageReview::importKeePass1(const QString& filename, const QString& p return db; } + +QSharedPointer ImportWizardPageReview::importProtonPass(const QString& filename) +{ + ProtonPassReader reader; + auto db = reader.convert(filename); + if (reader.hasError()) { + m_ui->messageWidget->showMessage(reader.errorString(), KMessageWidget::Error, -1); + } + return db; +} + +bool ImportWizardPageReview::isCsvImport() const +{ + return m_csvWidget && field("ImportType").toInt() == ImportWizard::IMPORT_CSV; +} + +QSharedPointer ImportWizardPageReview::importRemote(const QString& downloadCommand, + const QString& downloadInput, + const QString& password, + const QString& keyfile) +{ + auto* params = new RemoteParams(); + params->downloadCommand = downloadCommand; + params->downloadInput = downloadInput; + + auto result = m_remoteHandler->download(params); + + if (!result.success) { + m_ui->messageWidget->showMessage(result.errorMessage, KMessageWidget::Error, -1); + } + + auto key = QSharedPointer::create(); + + if (!password.isEmpty()) { + key->addKey(QSharedPointer::create(password)); + } + if (!keyfile.isEmpty()) { + QSharedPointer fileKey = QSharedPointer::create(); + if (Utils::loadFileKey(keyfile, fileKey)) { + key->addKey(fileKey); + } else { + m_ui->messageWidget->showMessage(tr("Could not load key file."), KMessageWidget::Error, -1); + } + } + + QString error; + QSharedPointer remoteDb = QSharedPointer::create(); + remoteDb->markAsTemporaryDatabase(); + if (!remoteDb->open(result.filePath, key, &error)) { + m_ui->messageWidget->showMessage( + tr("Could not open remote database. Password or key file may be incorrect."), KMessageWidget::Error, -1); + } + + return remoteDb; +} diff --git a/src/gui/wizard/ImportWizardPageReview.h b/src/gui/wizard/ImportWizardPageReview.h index 87f501c85..17f85a1a5 100644 --- a/src/gui/wizard/ImportWizardPageReview.h +++ b/src/gui/wizard/ImportWizardPageReview.h @@ -1,4 +1,4 @@ -/* +/* * Copyright (C) 2023 KeePassXC Team * * This program is free software: you can redistribute it and/or modify @@ -21,6 +21,12 @@ #include #include +#include +#include +#include + +#include "../remote/RemoteHandler.h" + class CsvImportWidget; class Database; namespace Ui @@ -43,11 +49,17 @@ public: QSharedPointer database(); private: + bool isCsvImport() const; void setupCsvImport(const QString& filename); QSharedPointer importOPUX(const QString& filename); QSharedPointer importBitwarden(const QString& filename, const QString& password); QSharedPointer importOPVault(const QString& filename, const QString& password); QSharedPointer importKeePass1(const QString& filename, const QString& password, const QString& keyfile); + QSharedPointer importProtonPass(const QString& filename); + QSharedPointer importRemote(const QString& downloadCommand, + const QString& downloadInput, + const QString& password, + const QString& keyfile); void setupDatabasePreview(); @@ -55,6 +67,7 @@ private: QSharedPointer m_db; QPointer m_csvWidget; + QPointer m_remoteHandler; }; #endif diff --git a/src/gui/wizard/ImportWizardPageSelect.cpp b/src/gui/wizard/ImportWizardPageSelect.cpp index 05b8f0990..ba5f28521 100644 --- a/src/gui/wizard/ImportWizardPageSelect.cpp +++ b/src/gui/wizard/ImportWizardPageSelect.cpp @@ -25,6 +25,8 @@ #include "gui/Icons.h" #include "gui/MainWindow.h" +#include + ImportWizardPageSelect::ImportWizardPageSelect(QWidget* parent) : QWizardPage(parent) , m_ui(new Ui::ImportWizardPageSelect()) @@ -35,13 +37,17 @@ ImportWizardPageSelect::ImportWizardPageSelect(QWidget* parent) new QListWidgetItem(icons()->icon("onepassword"), tr("1Password Export (.1pux)"), m_ui->importTypeList); new QListWidgetItem(icons()->icon("onepassword"), tr("1Password Vault (.opvault)"), m_ui->importTypeList); new QListWidgetItem(icons()->icon("bitwarden"), tr("Bitwarden (.json)"), m_ui->importTypeList); + new QListWidgetItem(icons()->icon("proton"), tr("Proton Pass (.json)"), m_ui->importTypeList); + new QListWidgetItem(icons()->icon("web"), tr("Remote Database (.kdbx)"), m_ui->importTypeList); new QListWidgetItem(icons()->icon("object-locked"), tr("KeePass 1 Database (.kdb)"), m_ui->importTypeList); m_ui->importTypeList->item(0)->setData(Qt::UserRole, ImportWizard::IMPORT_CSV); m_ui->importTypeList->item(1)->setData(Qt::UserRole, ImportWizard::IMPORT_OPUX); m_ui->importTypeList->item(2)->setData(Qt::UserRole, ImportWizard::IMPORT_OPVAULT); m_ui->importTypeList->item(3)->setData(Qt::UserRole, ImportWizard::IMPORT_BITWARDEN); - m_ui->importTypeList->item(4)->setData(Qt::UserRole, ImportWizard::IMPORT_KEEPASS1); + m_ui->importTypeList->item(4)->setData(Qt::UserRole, ImportWizard::IMPORT_PROTONPASS); + m_ui->importTypeList->item(5)->setData(Qt::UserRole, ImportWizard::IMPORT_REMOTE); + m_ui->importTypeList->item(6)->setData(Qt::UserRole, ImportWizard::IMPORT_KEEPASS1); connect(m_ui->importTypeList, &QListWidget::currentItemChanged, this, &ImportWizardPageSelect::itemSelected); m_ui->importTypeList->setCurrentRow(0); @@ -54,11 +60,22 @@ ImportWizardPageSelect::ImportWizardPageSelect(QWidget* parent) updateDatabaseChoices(); + m_ui->downloadCommandHelpButton->setIcon(icons()->icon("system-help")); + connect(m_ui->downloadCommandHelpButton, &QToolButton::clicked, this, [] { + QDesktopServices::openUrl(QUrl("https://keepassxc.org/docs/KeePassXC_UserGuide#_remote_database_support")); + }); + + connect(m_ui->importFileEdit, &QLineEdit::textChanged, this, &QWizardPage::completeChanged); + connect(m_ui->downloadCommand, &QLineEdit::textChanged, this, &QWizardPage::completeChanged); + registerField("ImportType", this); - registerField("ImportFile*", m_ui->importFileEdit); - registerField("ImportInto", m_ui->importIntoLabel); + registerField("ImportFile", m_ui->importFileEdit); + registerField("ImportIntoType", m_ui->importIntoGroupBox); // This is intentional + registerField("ImportInto", m_ui->importIntoLabel); // This is intentional registerField("ImportPassword", m_ui->passwordEdit, "text", "textChanged"); registerField("ImportKeyFile", m_ui->keyFileEdit); + registerField("DownloadCommand", m_ui->downloadCommand); + registerField("DownloadInput", m_ui->downloadCommandInput, "plainText", "textChanged"); } ImportWizardPageSelect::~ImportWizardPageSelect() @@ -77,14 +94,27 @@ bool ImportWizardPageSelect::validatePage() if (m_ui->existingDatabaseChoice->currentIndex() == -1) { return false; } + setField("ImportIntoType", ImportWizard::EXISTING_DATABASE); setField("ImportInto", m_ui->existingDatabaseChoice->currentData()); + } else if (m_ui->temporaryDatabaseRadio->isChecked()) { + setField("ImportIntoType", ImportWizard::TEMPORARY_DATABASE); + setField("ImportInto", {}); } else { + setField("ImportIntoType", ImportWizard::NEW_DATABASE); setField("ImportInto", {}); } return true; } +bool ImportWizardPageSelect::isComplete() const +{ + if (field("ImportType").toInt() == ImportWizard::IMPORT_REMOTE) { + return !field("DownloadCommand").toString().isEmpty(); + } + return !field("ImportFile").toString().isEmpty(); +} + void ImportWizardPageSelect::itemSelected(QListWidgetItem* current, QListWidgetItem* previous) { Q_UNUSED(previous) @@ -104,16 +134,24 @@ void ImportWizardPageSelect::itemSelected(QListWidgetItem* current, QListWidgetI // Unencrypted types case ImportWizard::IMPORT_CSV: case ImportWizard::IMPORT_OPUX: + case ImportWizard::IMPORT_PROTONPASS: setCredentialState(false); + setDownloadCommand(false); break; // Password may be required case ImportWizard::IMPORT_BITWARDEN: case ImportWizard::IMPORT_OPVAULT: setCredentialState(true); + setDownloadCommand(false); break; // Password and/or Key File may be required case ImportWizard::IMPORT_KEEPASS1: setCredentialState(true, true); + setDownloadCommand(false); + break; + case ImportWizard::IMPORT_REMOTE: + setCredentialState(true, true); + setDownloadCommand(true); break; default: Q_ASSERT(false); @@ -127,7 +165,7 @@ void ImportWizardPageSelect::updateDatabaseChoices() const if (mainWindow) { for (auto dbWidget : mainWindow->getOpenDatabases()) { // Remove all connections - disconnect(dbWidget, nullptr, nullptr, nullptr); + disconnect(dbWidget, nullptr, this, nullptr); // Skip over locked databases if (dbWidget->isLocked()) { @@ -228,6 +266,33 @@ void ImportWizardPageSelect::setCredentialState(bool passwordEnabled, bool keyFi } } +void ImportWizardPageSelect::setDownloadCommand(bool downloadCommandEnabled) +{ + bool downloadCommandStateChanged = m_ui->downloadCommandLabel->isVisible() != downloadCommandEnabled; + m_ui->downloadCommandLabel->setVisible(downloadCommandEnabled); + m_ui->downloadCommand->setVisible(downloadCommandEnabled); + m_ui->downloadCommandInputLabel->setVisible(downloadCommandEnabled); + m_ui->downloadCommandInput->setVisible(downloadCommandEnabled); + m_ui->downloadCommandHelpButton->setVisible(downloadCommandEnabled); + + m_ui->temporaryDatabaseRadio->setVisible(downloadCommandEnabled); + + m_ui->importFileLabel->setVisible(!downloadCommandEnabled); + m_ui->importFileEdit->setVisible(!downloadCommandEnabled); + m_ui->importFileButton->setVisible(!downloadCommandEnabled); + + // Workaround Qt bug where the wizard window is not updated when the internal layout changes + if (window()) { + int height = window()->height(); + if (downloadCommandStateChanged) { + auto diff = m_ui->downloadCommand->height() + m_ui->downloadCommandInput->height() + + m_ui->temporaryDatabaseRadio->height() + m_ui->inputFields->layout()->spacing(); + height += downloadCommandEnabled ? diff : -diff; + } + window()->resize(window()->width(), height); + } +} + QString ImportWizardPageSelect::importFileFilter() { switch (field("ImportType").toInt()) { @@ -237,6 +302,8 @@ QString ImportWizardPageSelect::importFileFilter() return QString("%1 (*.1pux)").arg(tr("1Password Export")); case ImportWizard::IMPORT_BITWARDEN: return QString("%1 (*.json)").arg(tr("Bitwarden JSON Export")); + case ImportWizard::IMPORT_PROTONPASS: + return QString("%1 (*.json)").arg(tr("Proton Pass JSON Export")); case ImportWizard::IMPORT_OPVAULT: return QString("%1 (*.opvault)").arg(tr("1Password Vault")); case ImportWizard::IMPORT_KEEPASS1: diff --git a/src/gui/wizard/ImportWizardPageSelect.h b/src/gui/wizard/ImportWizardPageSelect.h index 029865a56..5c4024ea5 100644 --- a/src/gui/wizard/ImportWizardPageSelect.h +++ b/src/gui/wizard/ImportWizardPageSelect.h @@ -39,6 +39,7 @@ public: void initializePage() override; bool validatePage() override; + bool isComplete() const override; private slots: void itemSelected(QListWidgetItem* current, QListWidgetItem* previous); @@ -49,6 +50,7 @@ private slots: private: QString importFileFilter(); void setCredentialState(bool passwordEnabled, bool keyFileEnable = false); + void setDownloadCommand(bool downloadCommandEnabled); QScopedPointer m_ui; }; diff --git a/src/gui/wizard/ImportWizardPageSelect.ui b/src/gui/wizard/ImportWizardPageSelect.ui index 6a7c8adad..ca37fec71 100644 --- a/src/gui/wizard/ImportWizardPageSelect.ui +++ b/src/gui/wizard/ImportWizardPageSelect.ui @@ -94,14 +94,14 @@ QLayout::SetMinimumSize - + Import File: - + @@ -115,24 +115,24 @@ - + Password: - + - + Key File: - + @@ -146,7 +146,7 @@ - + Qt::Vertical @@ -162,7 +162,7 @@ - + Import Into: @@ -172,7 +172,7 @@ - + @@ -239,9 +239,64 @@ + + + + Temporary Database + + + + + + + Command: + + + + + + + + + e.g.: "sftp user@hostname" or "scp user@hostname:DatabaseOnRemote.kdbx {TEMP_DATABASE}" + + + + + + + + + + + + + + + + Input: + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop + + + + + + + e.g.: +get DatabaseOnRemote.kdbx {TEMP_DATABASE} +exit +--- +{TEMP_DATABASE} is used as placeholder to store the database in a temporary location +The command has to exit. In case of `sftp` as last commend `exit` has to be sent + + + + diff --git a/src/gui/wizard/NewDatabaseWizard.cpp b/src/gui/wizard/NewDatabaseWizard.cpp index 03bede632..7394e1fc5 100644 --- a/src/gui/wizard/NewDatabaseWizard.cpp +++ b/src/gui/wizard/NewDatabaseWizard.cpp @@ -63,9 +63,7 @@ NewDatabaseWizard::NewDatabaseWizard(QWidget* parent) pageFrame->setPalette(framePalette); } -NewDatabaseWizard::~NewDatabaseWizard() -{ -} +NewDatabaseWizard::~NewDatabaseWizard() = default; bool NewDatabaseWizard::validateCurrentPage() { diff --git a/src/gui/wizard/NewDatabaseWizardPage.cpp b/src/gui/wizard/NewDatabaseWizardPage.cpp index 3188854c2..17dcaa673 100644 --- a/src/gui/wizard/NewDatabaseWizardPage.cpp +++ b/src/gui/wizard/NewDatabaseWizardPage.cpp @@ -1,6 +1,6 @@ /* - * Copyright (C) 2018 KeePassXC Team + * Copyright (C) 2023 KeePassXC Team * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -29,9 +29,7 @@ NewDatabaseWizardPage::NewDatabaseWizardPage(QWidget* parent) m_ui->setupUi(this); } -NewDatabaseWizardPage::~NewDatabaseWizardPage() -{ -} +NewDatabaseWizardPage::~NewDatabaseWizardPage() = default; /** * Set the database settings page widget for this wizard page. @@ -71,7 +69,7 @@ void NewDatabaseWizardPage::initializePage() return; } - m_pageWidget->load(m_db); + m_pageWidget->loadSettings(m_db); } bool NewDatabaseWizardPage::validatePage() @@ -81,7 +79,7 @@ bool NewDatabaseWizardPage::validatePage() return false; } - bool valid = m_pageWidget->save(); + bool valid = m_pageWidget->saveSettings(); m_pageWidget->uninitialize(); return valid; } diff --git a/src/gui/wizard/NewDatabaseWizardPageDatabaseKey.cpp b/src/gui/wizard/NewDatabaseWizardPageDatabaseKey.cpp index 3cd2abd31..b8847a141 100644 --- a/src/gui/wizard/NewDatabaseWizardPageDatabaseKey.cpp +++ b/src/gui/wizard/NewDatabaseWizardPageDatabaseKey.cpp @@ -27,6 +27,4 @@ NewDatabaseWizardPageDatabaseKey::NewDatabaseWizardPageDatabaseKey(QWidget* pare setSubTitle(tr("A set of credentials known only to you that protects your database.")); } -NewDatabaseWizardPageDatabaseKey::~NewDatabaseWizardPageDatabaseKey() -{ -} +NewDatabaseWizardPageDatabaseKey::~NewDatabaseWizardPageDatabaseKey() = default; diff --git a/src/gui/wizard/NewDatabaseWizardPageEncryption.cpp b/src/gui/wizard/NewDatabaseWizardPageEncryption.cpp index 743f7bcc2..d97abf1f4 100644 --- a/src/gui/wizard/NewDatabaseWizardPageEncryption.cpp +++ b/src/gui/wizard/NewDatabaseWizardPageEncryption.cpp @@ -28,6 +28,4 @@ NewDatabaseWizardPageEncryption::NewDatabaseWizardPageEncryption(QWidget* parent "Don't worry, you can change them later in the database settings.")); } -NewDatabaseWizardPageEncryption::~NewDatabaseWizardPageEncryption() -{ -} +NewDatabaseWizardPageEncryption::~NewDatabaseWizardPageEncryption() = default; diff --git a/src/gui/wizard/NewDatabaseWizardPageMetaData.cpp b/src/gui/wizard/NewDatabaseWizardPageMetaData.cpp index f4e2712fb..4be680427 100644 --- a/src/gui/wizard/NewDatabaseWizardPageMetaData.cpp +++ b/src/gui/wizard/NewDatabaseWizardPageMetaData.cpp @@ -27,6 +27,4 @@ NewDatabaseWizardPageMetaData::NewDatabaseWizardPageMetaData(QWidget* parent) setSubTitle(tr("Please fill in the display name and an optional description for your new database:")); } -NewDatabaseWizardPageMetaData::~NewDatabaseWizardPageMetaData() -{ -} \ No newline at end of file +NewDatabaseWizardPageMetaData::~NewDatabaseWizardPageMetaData() = default; diff --git a/src/keeshare/CMakeLists.txt b/src/keeshare/CMakeLists.txt index 5f7a39658..5fe739b36 100644 --- a/src/keeshare/CMakeLists.txt +++ b/src/keeshare/CMakeLists.txt @@ -2,7 +2,6 @@ if(WITH_XC_KEESHARE) set(keeshare_SOURCES SettingsPageKeeShare.cpp SettingsWidgetKeeShare.cpp - DatabaseSettingsPageKeeShare.cpp DatabaseSettingsWidgetKeeShare.cpp group/EditGroupWidgetKeeShare.cpp group/EditGroupPageKeeShare.cpp diff --git a/src/keeshare/DatabaseSettingsPageKeeShare.cpp b/src/keeshare/DatabaseSettingsPageKeeShare.cpp deleted file mode 100644 index f197c3e66..000000000 --- a/src/keeshare/DatabaseSettingsPageKeeShare.cpp +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright (C) 2018 KeePassXC Team - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 2 or (at your option) - * version 3 of the License. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include "DatabaseSettingsPageKeeShare.h" - -#include "core/Database.h" -#include "gui/Icons.h" -#include "keeshare/DatabaseSettingsWidgetKeeShare.h" - -QString DatabaseSettingsPageKeeShare::name() -{ - return "KeeShare"; -} - -QIcon DatabaseSettingsPageKeeShare::icon() -{ - return icons()->icon("preferences-system-network-sharing"); -} - -QWidget* DatabaseSettingsPageKeeShare::createWidget() -{ - return new DatabaseSettingsWidgetKeeShare(); -} - -void DatabaseSettingsPageKeeShare::loadSettings(QWidget* widget, QSharedPointer db) -{ - DatabaseSettingsWidgetKeeShare* settingsWidget = reinterpret_cast(widget); - settingsWidget->loadSettings(db); -} - -void DatabaseSettingsPageKeeShare::saveSettings(QWidget* widget) -{ - DatabaseSettingsWidgetKeeShare* settingsWidget = reinterpret_cast(widget); - settingsWidget->saveSettings(); -} diff --git a/src/keeshare/DatabaseSettingsWidgetKeeShare.cpp b/src/keeshare/DatabaseSettingsWidgetKeeShare.cpp index e72a86384..c0fdc4985 100644 --- a/src/keeshare/DatabaseSettingsWidgetKeeShare.cpp +++ b/src/keeshare/DatabaseSettingsWidgetKeeShare.cpp @@ -1,6 +1,6 @@ /* - * Copyright (C) 2018 KeePassXC Team + * Copyright (C) 2023 KeePassXC Team * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -36,7 +36,7 @@ DatabaseSettingsWidgetKeeShare::~DatabaseSettingsWidgetKeeShare() { } -void DatabaseSettingsWidgetKeeShare::loadSettings(QSharedPointer db) +void DatabaseSettingsWidgetKeeShare::loadSettings(const QSharedPointer& db) { m_db = db; diff --git a/src/keeshare/DatabaseSettingsWidgetKeeShare.h b/src/keeshare/DatabaseSettingsWidgetKeeShare.h index bebc0feeb..765bc3a36 100644 --- a/src/keeshare/DatabaseSettingsWidgetKeeShare.h +++ b/src/keeshare/DatabaseSettingsWidgetKeeShare.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2018 KeePassXC Team + * Copyright (C) 2023 KeePassXC Team * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -37,7 +37,7 @@ public: explicit DatabaseSettingsWidgetKeeShare(QWidget* parent = nullptr); ~DatabaseSettingsWidgetKeeShare(); - void loadSettings(QSharedPointer db); + void loadSettings(const QSharedPointer& db); void saveSettings(); private: diff --git a/src/keeshare/ShareExport.cpp b/src/keeshare/ShareExport.cpp index 49fa128b8..1a64ccde0 100644 --- a/src/keeshare/ShareExport.cpp +++ b/src/keeshare/ShareExport.cpp @@ -53,7 +53,7 @@ namespace continue; } // We could do more sophisticated **** trying to point the reference to the next in-scope reference - // but those cases with high propability constructed examples and very rare in real usage + // but those cases with high probability constructed examples and very rare in real usage const auto* sourceReference = sourceDb->rootGroup()->findEntryByUuid(targetEntry->uuid()); const auto resolvedValue = sourceReference->resolveMultiplePlaceholders(standardValue); targetEntry->setUpdateTimeinfo(false); @@ -172,7 +172,7 @@ ShareObserver::Result ShareExport::intoContainer(const QString& resolvedPath, KeePass2Writer writer; if (!writer.writeDatabase(&buffer, targetDb.data())) { - qWarning("Serializing export dabase failed: %s.", writer.errorString().toLatin1().data()); + qWarning("Serializing export database failed: %s.", writer.errorString().toLatin1().data()); return {reference.path, ShareObserver::Result::Error, writer.errorString()}; } @@ -201,7 +201,7 @@ ShareObserver::Result ShareExport::intoContainer(const QString& resolvedPath, } else { QString error; if (!targetDb->saveAs(resolvedPath, Database::Atomic, {}, &error)) { - qWarning("Exporting dabase failed: %s.", error.toLatin1().data()); + qWarning("Exporting database failed: %s.", error.toLatin1().data()); return {resolvedPath, ShareObserver::Result::Error, error}; } } diff --git a/src/keys/ChallengeResponseKey.cpp b/src/keys/ChallengeResponseKey.cpp index 6502e3714..eb52b7d09 100644 --- a/src/keys/ChallengeResponseKey.cpp +++ b/src/keys/ChallengeResponseKey.cpp @@ -30,7 +30,7 @@ ChallengeResponseKey::ChallengeResponseKey(YubiKeySlot keySlot) QByteArray ChallengeResponseKey::rawKey() const { - return QByteArray(m_key.data(), m_key.size()); + return {m_key.data(), static_cast(m_key.size())}; } void ChallengeResponseKey::setRawKey(const QByteArray&) diff --git a/src/keys/FileKey.cpp b/src/keys/FileKey.cpp index b50ffb30a..167b0462d 100644 --- a/src/keys/FileKey.cpp +++ b/src/keys/FileKey.cpp @@ -161,7 +161,7 @@ bool FileKey::load(const QString& fileName, QString* errorMsg) */ QByteArray FileKey::rawKey() const { - return QByteArray(m_key.data(), m_key.size()); + return {m_key.data(), int(m_key.size())}; } void FileKey::setRawKey(const QByteArray& data) diff --git a/src/keys/PasswordKey.cpp b/src/keys/PasswordKey.cpp index 60006dc30..7e0670647 100644 --- a/src/keys/PasswordKey.cpp +++ b/src/keys/PasswordKey.cpp @@ -44,7 +44,7 @@ QByteArray PasswordKey::rawKey() const if (!m_isInitialized) { return {}; } - return QByteArray(m_key.data(), m_key.size()); + return {m_key.data(), int(m_key.size())}; } void PasswordKey::setRawKey(const QByteArray& data) diff --git a/src/keys/drivers/YubiKey.cpp b/src/keys/drivers/YubiKey.cpp index cac5283d8..c07bcc072 100644 --- a/src/keys/drivers/YubiKey.cpp +++ b/src/keys/drivers/YubiKey.cpp @@ -24,7 +24,7 @@ #include #include -QMutex YubiKey::s_interfaceMutex(QMutex::Recursive); +QMutex YubiKey::s_interfaceMutex; YubiKey::YubiKey() { @@ -75,12 +75,21 @@ bool YubiKey::findValidKeys() { QMutexLocker lock(&s_interfaceMutex); - m_usbKeys = YubiKeyInterfaceUSB::instance()->findValidKeys(); - m_pcscKeys = YubiKeyInterfacePCSC::instance()->findValidKeys(); + findValidKeys(lock); return !m_usbKeys.isEmpty() || !m_pcscKeys.isEmpty(); } +void YubiKey::findValidKeys(const QMutexLocker& locker) +{ + // Check QMutexLocker since version 6.4 + Q_UNUSED(locker); + + m_connectedKeys = 0; + m_usbKeys = YubiKeyInterfaceUSB::instance()->findValidKeys(m_connectedKeys); + m_pcscKeys = YubiKeyInterfacePCSC::instance()->findValidKeys(m_connectedKeys); +} + void YubiKey::findValidKeysAsync() { QtConcurrent::run([this] { emit detectComplete(findValidKeys()); }); @@ -89,19 +98,19 @@ void YubiKey::findValidKeysAsync() YubiKey::KeyMap YubiKey::foundKeys() { QMutexLocker lock(&s_interfaceMutex); - KeyMap foundKeys; - - for (auto i = m_usbKeys.cbegin(); i != m_usbKeys.cend(); ++i) { - foundKeys.insert(i.key(), i.value()); - } - - for (auto i = m_pcscKeys.cbegin(); i != m_pcscKeys.cend(); ++i) { - foundKeys.insert(i.key(), i.value()); - } + KeyMap foundKeys = m_usbKeys; + foundKeys.unite(m_pcscKeys); return foundKeys; } +int YubiKey::connectedKeys() +{ + QMutexLocker lock(&s_interfaceMutex); + + return m_connectedKeys; +} + QString YubiKey::errorMessage() { QMutexLocker lock(&s_interfaceMutex); @@ -172,7 +181,7 @@ YubiKey::challenge(YubiKeySlot slot, const QByteArray& challenge, Botan::secure_ // Make sure we tried to find available keys if (m_usbKeys.isEmpty() && m_pcscKeys.isEmpty()) { - findValidKeys(); + findValidKeys(lock); } if (m_usbKeys.contains(slot)) { diff --git a/src/keys/drivers/YubiKey.h b/src/keys/drivers/YubiKey.h index 0eab12986..5578fd8df 100644 --- a/src/keys/drivers/YubiKey.h +++ b/src/keys/drivers/YubiKey.h @@ -24,6 +24,7 @@ #include #include #include + #include typedef QPair YubiKeySlot; @@ -37,7 +38,8 @@ class YubiKey : public QObject Q_OBJECT public: - typedef QMap KeyMap; + using KeyMap = QMap; + enum class ChallengeResult : int { YCR_ERROR = 0, @@ -52,6 +54,7 @@ public: void findValidKeysAsync(); KeyMap foundKeys(); + int connectedKeys(); ChallengeResult challenge(YubiKeySlot slot, const QByteArray& challenge, Botan::secure_vector& response); bool testChallenge(YubiKeySlot slot, bool* wouldBlock = nullptr); @@ -81,6 +84,8 @@ signals: private: explicit YubiKey(); + void findValidKeys(const QMutexLocker& locker); + static YubiKey* m_instance; QTimer m_interactionTimer; @@ -92,6 +97,8 @@ private: KeyMap m_usbKeys; KeyMap m_pcscKeys; + int m_connectedKeys = 0; + Q_DISABLE_COPY(YubiKey) }; diff --git a/src/keys/drivers/YubiKeyInterface.h b/src/keys/drivers/YubiKeyInterface.h index 51b4ae846..276f520a6 100644 --- a/src/keys/drivers/YubiKeyInterface.h +++ b/src/keys/drivers/YubiKeyInterface.h @@ -32,7 +32,7 @@ class YubiKeyInterface : public QObject public: bool isInitialized() const; - virtual YubiKey::KeyMap findValidKeys() = 0; + virtual YubiKey::KeyMap findValidKeys(int& connectedKeys) = 0; virtual YubiKey::ChallengeResult challenge(YubiKeySlot slot, const QByteArray& challenge, Botan::secure_vector& response) = 0; virtual bool testChallenge(YubiKeySlot slot, bool* wouldBlock) = 0; diff --git a/src/keys/drivers/YubiKeyInterfacePCSC.cpp b/src/keys/drivers/YubiKeyInterfacePCSC.cpp index 0d25ac434..765d3d0d8 100644 --- a/src/keys/drivers/YubiKeyInterfacePCSC.cpp +++ b/src/keys/drivers/YubiKeyInterfacePCSC.cpp @@ -20,6 +20,8 @@ #include "core/Tools.h" #include "crypto/Random.h" +#include + // MSYS2 does not define these macros // So set them to the value used by pcsc-lite #ifndef MAX_ATR_SIZE @@ -70,7 +72,8 @@ namespace rv = SCardListReaders(context, nullptr, nullptr, &dwReaders); // On windows, USB hot-plugging causes the underlying API server to die // So on every USB unplug event, the API context has to be recreated - if (rv == SCARD_E_SERVICE_STOPPED) { + // On Linux, restarting the pcsc daemon causes the API server to die as well + if (rv == SCARD_E_SERVICE_STOPPED || rv == SCARD_E_NO_SERVICE) { // Dont care if the release works since the handle might be broken SCardReleaseContext(context); rv = SCardEstablishContext(SCARD_SCOPE_SYSTEM, nullptr, nullptr, &context); @@ -107,7 +110,7 @@ namespace rv = SCardListReaders(context, nullptr, mszReaders, &dwReaders); if (rv == SCARD_S_SUCCESS) { char* readhead = mszReaders; - // Names are seperated by a null byte + // Names are separated by a null byte // The list is terminated by two null bytes while (*readhead != '\0') { QString reader = QString::fromUtf8(readhead); @@ -510,7 +513,6 @@ namespace return rv; }); } - } // namespace YubiKeyInterfacePCSC::YubiKeyInterfacePCSC() @@ -541,7 +543,7 @@ YubiKeyInterfacePCSC* YubiKeyInterfacePCSC::instance() return m_instance; } -YubiKey::KeyMap YubiKeyInterfacePCSC::findValidKeys() +YubiKey::KeyMap YubiKeyInterfacePCSC::findValidKeys(int& connectedKeys) { m_error.clear(); if (!isInitialized()) { @@ -577,6 +579,8 @@ YubiKey::KeyMap YubiKeyInterfacePCSC::findValidKeys() continue; } + auto finally = qScopeGuard([hCard]() { SCardDisconnect(hCard, SCARD_LEAVE_CARD); }); + // Read the protocol and the ATR record char pbReader[MAX_READERNAME] = {0}; SCUINT dwReaderLen = sizeof(pbReader); @@ -604,6 +608,8 @@ YubiKey::KeyMap YubiKeyInterfacePCSC::findValidKeys() unsigned int serial = 0; getSerial(satr, serial); + ++connectedKeys; + /* This variable indicates that the key is locked / timed out. When using the key via NFC, the user has to re-present the key to clear the timeout. Also, the key can be programmatically reset (see below). @@ -692,7 +698,7 @@ YubiKeyInterfacePCSC::challenge(YubiKeySlot slot, const QByteArray& challenge, B So we wait for the user to re-present it to clear the time-out This condition usually only happens when the key times out after the initial key listing, because performTestChallenge implicitly - resets the key (see commnt above) */ + resets the key (see comment above) */ if (ret == YubiKey::ChallengeResult::YCR_SUCCESS) { emit challengeCompleted(); return ret; @@ -735,7 +741,7 @@ YubiKey::ChallengeResult YubiKeyInterfacePCSC::performChallenge(void* key, * configurations even work, some docs say avoid it. * * In fact, the Yubikey always assumes the last byte (nr. 64) - * and all bytes of the same value preceeding it to be padding. + * and all bytes of the same value preceding it to be padding. * This does not conform fully to PKCS7, because the the actual value * of the padding bytes is ignored. */ diff --git a/src/keys/drivers/YubiKeyInterfacePCSC.h b/src/keys/drivers/YubiKeyInterfacePCSC.h index df4f25ba3..b91efe38e 100644 --- a/src/keys/drivers/YubiKeyInterfacePCSC.h +++ b/src/keys/drivers/YubiKeyInterfacePCSC.h @@ -52,7 +52,7 @@ class YubiKeyInterfacePCSC : public YubiKeyInterface public: static YubiKeyInterfacePCSC* instance(); - YubiKey::KeyMap findValidKeys() override; + YubiKey::KeyMap findValidKeys(int& connectedKeys) override; YubiKey::ChallengeResult challenge(YubiKeySlot slot, const QByteArray& challenge, Botan::secure_vector& response) override; diff --git a/src/keys/drivers/YubiKeyInterfaceUSB.cpp b/src/keys/drivers/YubiKeyInterfaceUSB.cpp index fde232d6f..a39b39dce 100644 --- a/src/keys/drivers/YubiKeyInterfaceUSB.cpp +++ b/src/keys/drivers/YubiKeyInterfaceUSB.cpp @@ -18,7 +18,6 @@ #include "YubiKeyInterfaceUSB.h" -#include "core/Tools.h" #include "crypto/Random.h" #include "thirdparty/ykcore/ykcore.h" #include "thirdparty/ykcore/ykstatus.h" @@ -27,7 +26,15 @@ namespace { constexpr int MAX_KEYS = 4; - YK_KEY* openKey(int index) + void closeKey(YK_KEY* key) + { + yk_close_key(key); + } + + using Yubikey = std::unique_ptr; + using YubikeyStatus = std::unique_ptr; + + Yubikey openKey(int index) { static const int vids[] = {YUBICO_VID, ONLYKEY_VID}; static const int pids[] = {YUBIKEY_PID, @@ -42,12 +49,9 @@ namespace PLUS_U2F_OTP_PID, ONLYKEY_PID}; - return yk_open_key_vid_pid(vids, sizeof(vids) / sizeof(vids[0]), pids, sizeof(pids) / sizeof(pids[0]), index); - } - - void closeKey(YK_KEY* key) - { - yk_close_key(key); + return Yubikey{ + yk_open_key_vid_pid(vids, sizeof(vids) / sizeof(vids[0]), pids, sizeof(pids) / sizeof(pids[0]), index), + &closeKey}; } void printError() @@ -69,24 +73,25 @@ namespace return serial; } - YK_KEY* openKeySerial(unsigned int serial) + Yubikey openKeySerial(unsigned int serial) { for (int i = 0; i < MAX_KEYS; ++i) { - auto* yk_key = openKey(i); - if (yk_key) { + auto key = openKey(i); + if (key) { // If the provided serial number is 0, or the key matches the serial, return it - if (serial == 0 || getSerial(yk_key) == serial) { - return yk_key; + if (serial == 0 || getSerial(key.get()) == serial) { + return key; } - closeKey(yk_key); } else if (yk_errno == YK_ENOKEY) { // No more connected keys break; } printError(); } - return nullptr; + + return Yubikey{nullptr, &closeKey}; } + } // namespace YubiKeyInterfaceUSB::YubiKeyInterfaceUSB() @@ -114,7 +119,7 @@ YubiKeyInterfaceUSB* YubiKeyInterfaceUSB::instance() return m_instance; } -YubiKey::KeyMap YubiKeyInterfaceUSB::findValidKeys() +YubiKey::KeyMap YubiKeyInterfaceUSB::findValidKeys(int& connectedKeys) { m_error.clear(); if (!isInitialized()) { @@ -127,29 +132,30 @@ YubiKey::KeyMap YubiKeyInterfaceUSB::findValidKeys() for (int i = 0; i < MAX_KEYS; ++i) { auto yk_key = openKey(i); if (yk_key) { - auto serial = getSerial(yk_key); + auto serial = getSerial(yk_key.get()); if (serial == 0) { - closeKey(yk_key); continue; } - auto st = ykds_alloc(); - yk_get_status(yk_key, st); + ++connectedKeys; + + YubikeyStatus st{ykds_alloc(), &ykds_free}; + yk_get_status(yk_key.get(), st.get()); int vid, pid; - yk_get_key_vid_pid(yk_key, &vid, &pid); + yk_get_key_vid_pid(yk_key.get(), &vid, &pid); QString name = m_pid_names.value(pid, tr("Unknown")); if (vid == ONLYKEY_VID) { name = QStringLiteral("OnlyKey %ver"); } if (name.contains("%ver")) { - name = name.replace("%ver", QString::number(ykds_version_major(st))); + name = name.replace("%ver", QString::number(ykds_version_major(st.get()))); } bool wouldBlock; for (int slot = 1; slot <= 2; ++slot) { auto config = (slot == 1 ? CONFIG1_VALID : CONFIG2_VALID); - if (!(ykds_touch_level(st) & config)) { + if (!(ykds_touch_level(st.get()) & config)) { // Slot is not configured continue; } @@ -159,7 +165,7 @@ YubiKey::KeyMap YubiKeyInterfaceUSB::findValidKeys() auto display = tr("%1 [%2] - Slot %3", "YubiKey NEO display fields") .arg(name, QString::number(serial), QString::number(slot)); keyMap.insert({serial, slot}, display); - } else if (performTestChallenge(yk_key, slot, &wouldBlock)) { + } else if (performTestChallenge(yk_key.get(), slot, &wouldBlock)) { auto display = tr("%1 [%2] - Slot %3, %4", "YubiKey display fields") .arg(name, @@ -170,9 +176,6 @@ YubiKey::KeyMap YubiKeyInterfaceUSB::findValidKeys() keyMap.insert({serial, slot}, display); } } - - ykds_free(st); - closeKey(yk_key); } else if (yk_errno == YK_ENOKEY) { // No more keys are connected break; @@ -197,11 +200,11 @@ YubiKey::KeyMap YubiKeyInterfaceUSB::findValidKeys() bool YubiKeyInterfaceUSB::testChallenge(YubiKeySlot slot, bool* wouldBlock) { bool ret = false; - auto* yk_key = openKeySerial(slot.first); + auto yk_key = openKeySerial(slot.first); if (yk_key) { - ret = performTestChallenge(yk_key, slot.second, wouldBlock); + ret = performTestChallenge(yk_key.get(), slot.second, wouldBlock); } - closeKey(yk_key); + return ret; } @@ -237,7 +240,7 @@ YubiKeyInterfaceUSB::challenge(YubiKeySlot slot, const QByteArray& challenge, Bo return YubiKey::ChallengeResult::YCR_ERROR; } - auto* yk_key = openKeySerial(slot.first); + auto yk_key = openKeySerial(slot.first); if (!yk_key) { // Key with specified serial number is not connected m_error = @@ -246,9 +249,8 @@ YubiKeyInterfaceUSB::challenge(YubiKeySlot slot, const QByteArray& challenge, Bo } emit challengeStarted(); - auto ret = performChallenge(yk_key, slot.second, true, challenge, response); + auto ret = performChallenge(yk_key.get(), slot.second, true, challenge, response); - closeKey(yk_key); emit challengeCompleted(); return ret; diff --git a/src/keys/drivers/YubiKeyInterfaceUSB.h b/src/keys/drivers/YubiKeyInterfaceUSB.h index 07c8118b7..9d5835f07 100644 --- a/src/keys/drivers/YubiKeyInterfaceUSB.h +++ b/src/keys/drivers/YubiKeyInterfaceUSB.h @@ -35,7 +35,7 @@ public: static constexpr int YUBICO_USB_VID = YUBICO_VID; static constexpr int ONLYKEY_USB_VID = ONLYKEY_VID; - YubiKey::KeyMap findValidKeys() override; + YubiKey::KeyMap findValidKeys(int& connectedKeys) override; YubiKey::ChallengeResult challenge(YubiKeySlot slot, const QByteArray& challenge, Botan::secure_vector& response) override; diff --git a/src/keys/drivers/YubiKeyStub.cpp b/src/keys/drivers/YubiKeyStub.cpp index df07ab5f9..64771e77d 100644 --- a/src/keys/drivers/YubiKeyStub.cpp +++ b/src/keys/drivers/YubiKeyStub.cpp @@ -18,9 +18,7 @@ #include "YubiKey.h" -YubiKey::YubiKey() -{ -} +YubiKey::YubiKey() = default; YubiKey* YubiKey::m_instance(Q_NULLPTR); @@ -52,6 +50,11 @@ YubiKey::KeyMap YubiKey::foundKeys() return {}; } +int YubiKey::connectedKeys() +{ + return 0; +} + QString YubiKey::errorMessage() { return {}; diff --git a/src/main.cpp b/src/main.cpp index 6c3efea9d..2c4da4c1f 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -19,6 +19,7 @@ #include #include #include +#include #include #include "cli/Utils.h" @@ -52,10 +53,8 @@ int main(int argc, char** argv) { QT_REQUIRE_VERSION(argc, argv, QT_VERSION_STR) -#if QT_VERSION >= QT_VERSION_CHECK(5, 6, 0) QApplication::setAttribute(Qt::AA_EnableHighDpiScaling); QGuiApplication::setAttribute(Qt::AA_UseHighDpiPixmaps); -#endif #if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0) && defined(Q_OS_WIN) QGuiApplication::setHighDpiScaleFactorRoundingPolicy(Qt::HighDpiScaleFactorRoundingPolicy::PassThrough); #endif @@ -66,6 +65,12 @@ int main(int argc, char** argv) Application::setApplicationVersion(KEEPASSXC_VERSION); app.setProperty("KPXC_QUALIFIED_APPNAME", "org.keepassxc.KeePassXC"); + // HACK: Prevent long-running threads from deadlocking the program with only 1 CPU + // See https://github.com/keepassxreboot/keepassxc/issues/10391 + if (QThreadPool::globalInstance()->maxThreadCount() < 2) { + QThreadPool::globalInstance()->setMaxThreadCount(2); + } + QCommandLineParser parser; parser.setApplicationDescription(QObject::tr("KeePassXC - cross-platform password manager")); parser.addPositionalArgument( @@ -79,6 +84,7 @@ int main(int argc, char** argv) QCommandLineOption pwstdinOption("pw-stdin", QObject::tr("read password of the database from stdin")); QCommandLineOption allowScreenCaptureOption("allow-screencapture", QObject::tr("allow screenshots and app recording (Windows/macOS)")); + QCommandLineOption startMinimized("minimized", QObject::tr("start minimized to the system tray")); QCommandLineOption helpOption = parser.addHelpOption(); QCommandLineOption versionOption = parser.addVersionOption(); @@ -90,6 +96,7 @@ int main(int argc, char** argv) parser.addOption(pwstdinOption); parser.addOption(debugInfoOption); parser.addOption(allowScreenCaptureOption); + parser.addOption(startMinimized); parser.process(app); @@ -102,7 +109,7 @@ int main(int argc, char** argv) if (parser.isSet(debugInfoOption)) { QTextStream out(stdout, QIODevice::WriteOnly); QString debugInfo = Tools::debugInfo().append("\n").append(Crypto::debugInfo()); - out << debugInfo << endl; + out << debugInfo << Qt::endl; return EXIT_SUCCESS; } @@ -169,12 +176,12 @@ int main(int argc, char** argv) return EXIT_FAILURE; } + Utils::setDefaultTextStreams(); + // Apply the configured theme before creating any GUI elements app.applyTheme(); -#if QT_VERSION >= QT_VERSION_CHECK(5, 7, 0) QGuiApplication::setDesktopFileName(app.property("KPXC_QUALIFIED_APPNAME").toString() + QStringLiteral(".desktop")); -#endif Application::bootstrap(config()->get(Config::GUI_Language).toString()); @@ -189,23 +196,20 @@ int main(int argc, char** argv) mainWindow.setAllowScreenCapture(parser.isSet(allowScreenCaptureOption)); const bool pwstdin = parser.isSet(pwstdinOption); - if (!fileNames.isEmpty() && pwstdin) { - Utils::setDefaultTextStreams(); - } for (const QString& filename : fileNames) { QString password; if (pwstdin) { // we always need consume a line of STDIN if --pw-stdin is set to clear out the // buffer for native messaging, even if the specified file does not exist QTextStream out(stdout, QIODevice::WriteOnly); - out << QObject::tr("Database password: ") << flush; + out << QObject::tr("Database password: ") << Qt::flush; password = Utils::getPassword(); } mainWindow.openDatabase(filename, password, parser.value(keyfileOption)); } // start minimized if configured - if (config()->get(Config::GUI_MinimizeOnStartup).toBool()) { + if (parser.isSet(startMinimized) || config()->get(Config::GUI_MinimizeOnStartup).toBool()) { mainWindow.hideWindow(); } else { mainWindow.bringToFront(); @@ -225,5 +229,7 @@ int main(int argc, char** argv) __lsan_disable(); #endif + Utils::resetTextStreams(); + return exitCode; } diff --git a/src/core/HibpDownloader.cpp b/src/networking/HibpDownloader.cpp similarity index 99% rename from src/core/HibpDownloader.cpp rename to src/networking/HibpDownloader.cpp index 9ff181093..8b09ce2c4 100644 --- a/src/core/HibpDownloader.cpp +++ b/src/networking/HibpDownloader.cpp @@ -16,7 +16,7 @@ */ #include "HibpDownloader.h" -#include "core/NetworkManager.h" +#include "NetworkManager.h" #include #include diff --git a/src/core/HibpDownloader.h b/src/networking/HibpDownloader.h similarity index 97% rename from src/core/HibpDownloader.h rename to src/networking/HibpDownloader.h index f8e66baf3..ccdc393ff 100644 --- a/src/core/HibpDownloader.h +++ b/src/networking/HibpDownloader.h @@ -62,8 +62,6 @@ private slots: void fetchReadyRead(); private: - void fetchPassword(const QString& password); - QStringList m_pwdsToTry; // The list of remaining passwords to validate QHash> m_replies; }; diff --git a/src/core/NetworkManager.cpp b/src/networking/NetworkManager.cpp similarity index 100% rename from src/core/NetworkManager.cpp rename to src/networking/NetworkManager.cpp diff --git a/src/core/NetworkManager.h b/src/networking/NetworkManager.h similarity index 100% rename from src/core/NetworkManager.h rename to src/networking/NetworkManager.h diff --git a/src/updatecheck/UpdateChecker.cpp b/src/networking/UpdateChecker.cpp similarity index 99% rename from src/updatecheck/UpdateChecker.cpp rename to src/networking/UpdateChecker.cpp index ff2240628..ea3d435df 100644 --- a/src/updatecheck/UpdateChecker.cpp +++ b/src/networking/UpdateChecker.cpp @@ -17,10 +17,10 @@ #include "UpdateChecker.h" +#include "NetworkManager.h" #include "config-keepassx.h" #include "core/Clock.h" #include "core/Config.h" -#include "core/NetworkManager.h" #include #include diff --git a/src/updatecheck/UpdateChecker.h b/src/networking/UpdateChecker.h similarity index 100% rename from src/updatecheck/UpdateChecker.h rename to src/networking/UpdateChecker.h diff --git a/src/post_install/CMakeLists.txt b/src/post_install/CMakeLists.txt index 359c891f3..1adc4740b 100644 --- a/src/post_install/CMakeLists.txt +++ b/src/post_install/CMakeLists.txt @@ -1,5 +1,5 @@ # The install commands in this subdirectory will be executed after all the install commands in the -# current scope are ran. It is required for correct functtioning of macdeployqt. +# current scope are ran. It is required for correct functioning of macdeployqt. if(APPLE AND WITH_APP_BUNDLE) # Run macdeloyqt on the main app and any extra binaries and plugins as specified by the diff --git a/src/proxy/CMakeLists.txt b/src/proxy/CMakeLists.txt old mode 100755 new mode 100644 diff --git a/src/quickunlock/Polkit.cpp b/src/quickunlock/Polkit.cpp new file mode 100644 index 000000000..d73a7c71b --- /dev/null +++ b/src/quickunlock/Polkit.cpp @@ -0,0 +1,247 @@ +/* + * Copyright (C) 2023 KeePassXC Team + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 or (at your option) + * version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "Polkit.h" + +#include "crypto/CryptoHash.h" +#include "crypto/Random.h" +#include "crypto/SymmetricCipher.h" +#include "gui/osutils/nixutils/NixUtils.h" + +#include +#include +#include +#include +#include + +extern "C" { +#include +} + +const QString polkit_service = "org.freedesktop.PolicyKit1"; +const QString polkit_object = "/org/freedesktop/PolicyKit1/Authority"; + +namespace +{ + QString getKeyName(const QUuid& dbUuid) + { + static const QString keyPrefix = "keepassxc_polkit_keys_"; + return keyPrefix + dbUuid.toString(); + } +} // namespace + +Polkit::Polkit() +{ + PolkitSubject::registerMetaType(); + PolkitAuthorizationResults::registerMetaType(); + + /* Note we explicitly use our own dbus path here, as the ::systemBus() method could be overridden + through an environment variable to return an alternative bus path. This bus could have an application + pretending to be polkit running on it, which could approve every authentication request + + Most Linux distros place the system bus at this exact path, so it is hard-coded. + For any other distros, this path will need to be patched before compilation. + */ + QDBusConnection bus = + QDBusConnection::connectToBus("unix:path=/run/dbus/system_bus_socket", "keepassxc_polkit_dbus"); + + m_available = bus.isConnected(); + if (!m_available) { + qDebug() << "polkit: Failed to connect to system dbus (this may be due to a non-standard dbus path)"; + return; + } + + m_available = bus.interface()->isServiceRegistered(polkit_service); + + if (!m_available) { + qDebug() << "polkit: Polkit is not registered on dbus"; + return; + } + + m_polkit.reset(new org::freedesktop::PolicyKit1::Authority(polkit_service, polkit_object, bus)); +} + +Polkit::~Polkit() +{ +} + +void Polkit::reset(const QUuid& dbUuid) +{ + m_encryptedMasterKeys.remove(dbUuid); +} + +bool Polkit::isAvailable() const +{ + return m_available; +} + +QString Polkit::errorString() const +{ + return m_error; +} + +void Polkit::reset() +{ + m_encryptedMasterKeys.clear(); +} + +bool Polkit::setKey(const QUuid& dbUuid, const QByteArray& key) +{ + reset(dbUuid); + + // Generate a random iv/key pair to encrypt the master password with + QByteArray randomKey = randomGen()->randomArray(SymmetricCipher::keySize(SymmetricCipher::Aes256_GCM)); + QByteArray randomIV = randomGen()->randomArray(SymmetricCipher::defaultIvSize(SymmetricCipher::Aes256_GCM)); + QByteArray keychainKeyValue = randomKey + randomIV; + + SymmetricCipher aes256Encrypt; + if (!aes256Encrypt.init(SymmetricCipher::Aes256_GCM, SymmetricCipher::Encrypt, randomKey, randomIV)) { + m_error = QObject::tr("AES initialization failed"); + return false; + } + + // Encrypt the master password + QByteArray encryptedMasterKey = key; + if (!aes256Encrypt.finish(encryptedMasterKey)) { + m_error = QObject::tr("AES encrypt failed"); + qDebug() << "polkit aes encrypt failed: " << aes256Encrypt.errorString(); + return false; + } + + // Add the iv/key pair into the linux keyring + key_serial_t key_serial = add_key("user", + getKeyName(dbUuid).toStdString().c_str(), + keychainKeyValue.constData(), + keychainKeyValue.size(), + KEY_SPEC_PROCESS_KEYRING); + if (key_serial < 0) { + m_error = QObject::tr("Failed to store in Linux Keyring"); + qDebug() << "polkit keyring failed to store: " << errno; + return false; + } + + // Scrub the keys from ram + Botan::secure_scrub_memory(randomKey.data(), randomKey.size()); + Botan::secure_scrub_memory(randomIV.data(), randomIV.size()); + Botan::secure_scrub_memory(keychainKeyValue.data(), keychainKeyValue.size()); + + // Store encrypted master password and return + m_encryptedMasterKeys.insert(dbUuid, encryptedMasterKey); + return true; +} + +bool Polkit::getKey(const QUuid& dbUuid, QByteArray& key) +{ + if (!m_polkit || !hasKey(dbUuid)) { + return false; + } + + PolkitSubject subject; + subject.kind = "unix-process"; + subject.details.insert("pid", static_cast(QCoreApplication::applicationPid())); + subject.details.insert("start-time", nixUtils()->getProcessStartTime()); + + QMap details; + + auto result = m_polkit->CheckAuthorization( + subject, + "org.keepassxc.KeePassXC.unlockDatabase", + details, + 0x00000001, + // AllowUserInteraction - wait for user to authenticate + // https://www.freedesktop.org/software/polkit/docs/0.105/eggdbus-interface-org.freedesktop.PolicyKit1.Authority.html#eggdbus-enum-CheckAuthorizationFlags + ""); + + // A general error occurred + if (result.isError()) { + auto msg = result.error().message(); + m_error = QObject::tr("Polkit returned an error: %1").arg(msg); + qDebug() << "polkit returned an error: " << msg; + return false; + } + + PolkitAuthorizationResults authResult = result.value(); + if (authResult.is_authorized) { + QByteArray encryptedMasterKey = m_encryptedMasterKeys.value(dbUuid); + key_serial_t keySerial = + find_key_by_type_and_desc("user", getKeyName(dbUuid).toStdString().c_str(), KEY_SPEC_PROCESS_KEYRING); + + if (keySerial == -1) { + m_error = QObject::tr("Could not locate key in keyring"); + qDebug() << "polkit keyring failed to find: " << errno; + return false; + } + + void* keychainBuffer; + long keychainDataSize = keyctl_read_alloc(keySerial, &keychainBuffer); + + if (keychainDataSize == -1) { + m_error = QObject::tr("Could not read key in keyring"); + qDebug() << "polkit keyring failed to read: " << errno; + return false; + } + + QByteArray keychainBytes(static_cast(keychainBuffer), keychainDataSize); + + Botan::secure_scrub_memory(keychainBuffer, keychainDataSize); + free(keychainBuffer); + + QByteArray keychainKey = keychainBytes.left(SymmetricCipher::keySize(SymmetricCipher::Aes256_GCM)); + QByteArray keychainIv = keychainBytes.right(SymmetricCipher::defaultIvSize(SymmetricCipher::Aes256_GCM)); + + SymmetricCipher aes256Decrypt; + if (!aes256Decrypt.init(SymmetricCipher::Aes256_GCM, SymmetricCipher::Decrypt, keychainKey, keychainIv)) { + m_error = QObject::tr("AES initialization failed"); + qDebug() << "polkit aes init failed"; + return false; + } + + key = encryptedMasterKey; + if (!aes256Decrypt.finish(key)) { + key.clear(); + m_error = QObject::tr("AES decrypt failed"); + qDebug() << "polkit aes decrypt failed: " << aes256Decrypt.errorString(); + return false; + } + + // Scrub the keys from ram + Botan::secure_scrub_memory(keychainKey.data(), keychainKey.size()); + Botan::secure_scrub_memory(keychainIv.data(), keychainIv.size()); + Botan::secure_scrub_memory(keychainBytes.data(), keychainBytes.size()); + Botan::secure_scrub_memory(encryptedMasterKey.data(), encryptedMasterKey.size()); + + return true; + } + + // Failed to authenticate + if (authResult.is_challenge) { + m_error = QObject::tr("No Polkit authentication agent was available"); + } else { + m_error = QObject::tr("Polkit authorization failed"); + } + + return false; +} + +bool Polkit::hasKey(const QUuid& dbUuid) const +{ + if (!m_encryptedMasterKeys.contains(dbUuid)) { + return false; + } + + return find_key_by_type_and_desc("user", getKeyName(dbUuid).toStdString().c_str(), KEY_SPEC_PROCESS_KEYRING) != -1; +} diff --git a/src/quickunlock/Polkit.h b/src/quickunlock/Polkit.h new file mode 100644 index 000000000..7dfc2db7b --- /dev/null +++ b/src/quickunlock/Polkit.h @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2023 KeePassXC Team + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 or (at your option) + * version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef KEEPASSX_POLKIT_H +#define KEEPASSX_POLKIT_H + +#include "QuickUnlockInterface.h" +#include "polkit_dbus.h" +#include +#include + +class Polkit : public QuickUnlockInterface +{ +public: + Polkit(); + ~Polkit() override; + + bool isAvailable() const override; + QString errorString() const override; + + bool setKey(const QUuid& dbUuid, const QByteArray& key) override; + bool getKey(const QUuid& dbUuid, QByteArray& key) override; + bool hasKey(const QUuid& dbUuid) const override; + + void reset(const QUuid& dbUuid) override; + void reset() override; + +private: + bool m_available; + QString m_error; + QHash m_encryptedMasterKeys; + + QScopedPointer m_polkit; +}; + +#endif // KEEPASSX_POLKIT_H diff --git a/src/quickunlock/PolkitDbusTypes.cpp b/src/quickunlock/PolkitDbusTypes.cpp new file mode 100644 index 000000000..a4305dc44 --- /dev/null +++ b/src/quickunlock/PolkitDbusTypes.cpp @@ -0,0 +1,45 @@ +#include "PolkitDbusTypes.h" + +void PolkitSubject::registerMetaType() +{ + qRegisterMetaType("PolkitSubject"); + qDBusRegisterMetaType(); +} + +QDBusArgument& operator<<(QDBusArgument& argument, const PolkitSubject& subject) +{ + argument.beginStructure(); + argument << subject.kind << subject.details; + argument.endStructure(); + return argument; +} + +const QDBusArgument& operator>>(const QDBusArgument& argument, PolkitSubject& subject) +{ + argument.beginStructure(); + argument >> subject.kind >> subject.details; + argument.endStructure(); + return argument; +} + +void PolkitAuthorizationResults::registerMetaType() +{ + qRegisterMetaType("PolkitAuthorizationResults"); + qDBusRegisterMetaType(); +} + +QDBusArgument& operator<<(QDBusArgument& argument, const PolkitAuthorizationResults& res) +{ + argument.beginStructure(); + argument << res.is_authorized << res.is_challenge << res.details; + argument.endStructure(); + return argument; +} + +const QDBusArgument& operator>>(const QDBusArgument& argument, PolkitAuthorizationResults& res) +{ + argument.beginStructure(); + argument >> res.is_authorized >> res.is_challenge >> res.details; + argument.endStructure(); + return argument; +} diff --git a/src/quickunlock/PolkitDbusTypes.h b/src/quickunlock/PolkitDbusTypes.h new file mode 100644 index 000000000..83eb23889 --- /dev/null +++ b/src/quickunlock/PolkitDbusTypes.h @@ -0,0 +1,36 @@ +#ifndef KEEPASSX_POLKITDBUSTYPES_H +#define KEEPASSX_POLKITDBUSTYPES_H + +#include + +class PolkitSubject +{ +public: + QString kind; + QVariantMap details; + + static void registerMetaType(); + + friend QDBusArgument& operator<<(QDBusArgument& argument, const PolkitSubject& subject); + + friend const QDBusArgument& operator>>(const QDBusArgument& argument, PolkitSubject& subject); +}; + +class PolkitAuthorizationResults +{ +public: + bool is_authorized; + bool is_challenge; + QMap details; + + static void registerMetaType(); + + friend QDBusArgument& operator<<(QDBusArgument& argument, const PolkitAuthorizationResults& subject); + + friend const QDBusArgument& operator>>(const QDBusArgument& argument, PolkitAuthorizationResults& subject); +}; + +Q_DECLARE_METATYPE(PolkitSubject); +Q_DECLARE_METATYPE(PolkitAuthorizationResults); + +#endif // KEEPASSX_POLKITDBUSTYPES_H diff --git a/src/quickunlock/QuickUnlockInterface.cpp b/src/quickunlock/QuickUnlockInterface.cpp new file mode 100644 index 000000000..0e24736e8 --- /dev/null +++ b/src/quickunlock/QuickUnlockInterface.cpp @@ -0,0 +1,81 @@ +/* + * Copyright (C) 2023 KeePassXC Team + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 or (at your option) + * version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "QuickUnlockInterface.h" +#include + +#if defined(Q_OS_MACOS) +#include "TouchID.h" +#define QUICKUNLOCK_IMPLEMENTATION TouchID +#elif defined(Q_CC_MSVC) +#include "WindowsHello.h" +#define QUICKUNLOCK_IMPLEMENTATION WindowsHello +#elif defined(Q_OS_LINUX) +#include "Polkit.h" +#define QUICKUNLOCK_IMPLEMENTATION Polkit +#else +#define QUICKUNLOCK_IMPLEMENTATION NoQuickUnlock +#endif + +QUICKUNLOCK_IMPLEMENTATION* quickUnlockInstance = {nullptr}; + +QuickUnlockInterface* getQuickUnlock() +{ + if (!quickUnlockInstance) { + quickUnlockInstance = new QUICKUNLOCK_IMPLEMENTATION(); + } + return quickUnlockInstance; +} + +bool NoQuickUnlock::isAvailable() const +{ + return false; +} + +QString NoQuickUnlock::errorString() const +{ + return QObject::tr("No Quick Unlock provider is available"); +} + +void NoQuickUnlock::reset() +{ +} + +bool NoQuickUnlock::setKey(const QUuid& dbUuid, const QByteArray& key) +{ + Q_UNUSED(dbUuid) + Q_UNUSED(key) + return false; +} + +bool NoQuickUnlock::getKey(const QUuid& dbUuid, QByteArray& key) +{ + Q_UNUSED(dbUuid) + Q_UNUSED(key) + return false; +} + +bool NoQuickUnlock::hasKey(const QUuid& dbUuid) const +{ + Q_UNUSED(dbUuid) + return false; +} + +void NoQuickUnlock::reset(const QUuid& dbUuid) +{ + Q_UNUSED(dbUuid) +} diff --git a/src/quickunlock/QuickUnlockInterface.h b/src/quickunlock/QuickUnlockInterface.h new file mode 100644 index 000000000..54aeb8a62 --- /dev/null +++ b/src/quickunlock/QuickUnlockInterface.h @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2023 KeePassXC Team + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 or (at your option) + * version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef KEEPASSXC_QUICKUNLOCKINTERFACE_H +#define KEEPASSXC_QUICKUNLOCKINTERFACE_H + +#include + +class QuickUnlockInterface +{ + Q_DISABLE_COPY(QuickUnlockInterface) + +public: + QuickUnlockInterface() = default; + virtual ~QuickUnlockInterface() = default; + + virtual bool isAvailable() const = 0; + virtual QString errorString() const = 0; + + virtual bool setKey(const QUuid& dbUuid, const QByteArray& key) = 0; + virtual bool getKey(const QUuid& dbUuid, QByteArray& key) = 0; + virtual bool hasKey(const QUuid& dbUuid) const = 0; + + virtual void reset(const QUuid& dbUuid) = 0; + virtual void reset() = 0; +}; + +class NoQuickUnlock : public QuickUnlockInterface +{ +public: + bool isAvailable() const override; + QString errorString() const override; + + bool setKey(const QUuid& dbUuid, const QByteArray& key) override; + bool getKey(const QUuid& dbUuid, QByteArray& key) override; + bool hasKey(const QUuid& dbUuid) const override; + + void reset(const QUuid& dbUuid) override; + void reset() override; +}; + +QuickUnlockInterface* getQuickUnlock(); + +#endif // KEEPASSXC_QUICKUNLOCKINTERFACE_H diff --git a/src/quickunlock/TouchID.h b/src/quickunlock/TouchID.h new file mode 100644 index 000000000..74e5d9474 --- /dev/null +++ b/src/quickunlock/TouchID.h @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2023 KeePassXC Team + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 or (at your option) + * version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef KEEPASSX_TOUCHID_H +#define KEEPASSX_TOUCHID_H + +#include "QuickUnlockInterface.h" +#include + +class TouchID : public QuickUnlockInterface +{ +public: + bool isAvailable() const override; + QString errorString() const override; + + bool setKey(const QUuid& dbUuid, const QByteArray& passwordKey) override; + bool getKey(const QUuid& dbUuid, QByteArray& passwordKey) override; + bool hasKey(const QUuid& dbUuid) const override; + + void reset(const QUuid& dbUuid = "") override; + void reset() override; + +private: + static bool isWatchAvailable(); + static bool isTouchIdAvailable(); + static bool isPasswordFallbackPossible(); + bool setKey(const QUuid& dbUuid, const QByteArray& passwordKey, const bool ignoreTouchID); + + static void deleteKeyEntry(const QString& accountName); + static QString databaseKeyName(const QUuid& dbUuid); + + QHash m_encryptedMasterKeys; +}; + +#endif // KEEPASSX_TOUCHID_H diff --git a/src/touchid/TouchID.mm b/src/quickunlock/TouchID.mm similarity index 72% rename from src/touchid/TouchID.mm rename to src/quickunlock/TouchID.mm index 045658f51..6368d7e6b 100644 --- a/src/touchid/TouchID.mm +++ b/src/quickunlock/TouchID.mm @@ -1,4 +1,4 @@ -#include "touchid/TouchID.h" +#include "quickunlock/TouchID.h" #include "crypto/Random.h" #include "crypto/SymmetricCipher.h" @@ -13,6 +13,7 @@ #include #include +#include #define TOUCH_ID_ENABLE_DEBUG_LOGS() 0 #if TOUCH_ID_ENABLE_DEBUG_LOGS() @@ -54,16 +55,6 @@ inline CFMutableDictionaryRef makeDictionary() { return CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); } -/** - * Singleton - */ -TouchID& TouchID::getInstance() -{ - static TouchID instance; // Guaranteed to be destroyed. - // Instantiated on first use. - return instance; -} - //! Try to delete an existing keychain entry void TouchID::deleteKeyEntry(const QString& accountName) { @@ -77,30 +68,38 @@ void TouchID::deleteKeyEntry(const QString& accountName) // get data from the KeyChain OSStatus status = SecItemDelete(query); - LogStatusError("TouchID::storeKey - Status deleting existing entry", status); + LogStatusError("TouchID::deleteKeyEntry - Status deleting existing entry", status); } -QString TouchID::databaseKeyName(const QString &databasePath) +QString TouchID::databaseKeyName(const QUuid& dbUuid) { static const QString keyPrefix = "KeepassXC_TouchID_Keys_"; - const QByteArray pathHash = CryptoHash::hash(databasePath.toUtf8(), CryptoHash::Sha256).toHex(); - return keyPrefix + pathHash; + return keyPrefix + dbUuid.toString(); } -/** - * Generates a random AES 256bit key and uses it to encrypt the PasswordKey that - * protects the database. The encrypted PasswordKey is kept in memory while the - * AES key is stored in the macOS KeyChain protected by either TouchID or Apple Watch. - */ -bool TouchID::storeKey(const QString& databasePath, const QByteArray& passwordKey) +QString TouchID::errorString() const { - if (databasePath.isEmpty() || passwordKey.isEmpty()) { - debug("TouchID::storeKey - illegal arguments"); + // TODO + return ""; +} + +void TouchID::reset() +{ + m_encryptedMasterKeys.clear(); +} + + + + +bool TouchID::setKey(const QUuid& dbUuid, const QByteArray& passwordKey, const bool ignoreTouchID) +{ + if (passwordKey.isEmpty()) { + debug("TouchID::setKey - illegal arguments"); return false; } - if (m_encryptedMasterKeys.contains(databasePath)) { - debug("TouchID::storeKey - Already stored key for this database"); + if (m_encryptedMasterKeys.contains(dbUuid)) { + debug("TouchID::setKey - Already stored key for this database"); return true; } @@ -110,7 +109,7 @@ bool TouchID::storeKey(const QString& databasePath, const QByteArray& passwordKe SymmetricCipher aes256Encrypt; if (!aes256Encrypt.init(SymmetricCipher::Aes256_GCM, SymmetricCipher::Encrypt, randomKey, randomIV)) { - debug("TouchID::storeKey - AES initialisation falied"); + debug("TouchID::setKey - AES initialisation failed"); return false; } @@ -121,7 +120,7 @@ bool TouchID::storeKey(const QString& databasePath, const QByteArray& passwordKe return false; } - const QString keyName = databaseKeyName(databasePath); + const QString keyName = databaseKeyName(dbUuid); deleteKeyEntry(keyName); // Try to delete the existing key entry @@ -130,29 +129,47 @@ bool TouchID::storeKey(const QString& databasePath, const QByteArray& passwordKe // We need both runtime and compile time checks here to solve the following problems: // - Not all flags are available in all OS versions, so we have to check it at compile time - // - Requesting Biometry/TouchID when to fingerprint sensor is available will result in runtime error + // - Requesting Biometry/TouchID/DevicePassword when to fingerprint sensor is available will result in runtime error SecAccessControlCreateFlags accessControlFlags = 0; - if (isTouchIdAvailable()) { #if XC_COMPILER_SUPPORT(APPLE_BIOMETRY) - // Prefer the non-deprecated flag when available - accessControlFlags = kSecAccessControlBiometryCurrentSet; -#elif XC_COMPILER_SUPPORT(TOUCH_ID) - accessControlFlags = kSecAccessControlTouchIDCurrentSet; -#endif + // Needs a special check to work with SecItemAdd, when TouchID is not enrolled and the flag + // is set, the method call fails with an error. But we want to still set this flag if TouchID is + // enrolled but temporarily unavailable due to closed lid + // + // At least on a Hackintosh the enrolled-check does not work, there LAErrorBiometryNotAvailable gets returned instead of + // LAErrorBiometryNotEnrolled. + // + // Thats kinda unfortunate, because now you cannot know for sure if TouchID hardware is either temporarily unavailable or not present + // at all, because LAErrorBiometryNotAvailable is used for both cases. + // + // So to make quick unlock fallbacks possible on these machines you have to try to save the key a second time without this flag, if the + // first try fails with an error. + if (!ignoreTouchID) { + // Prefer the non-deprecated flag when available + accessControlFlags = kSecAccessControlBiometryCurrentSet; } +#elif XC_COMPILER_SUPPORT(TOUCH_ID) + if (!ignoreTouchID) { + accessControlFlags = kSecAccessControlTouchIDCurrentSet; + } +#endif - if (isWatchAvailable()) { #if XC_COMPILER_SUPPORT(WATCH_UNLOCK) accessControlFlags = accessControlFlags | kSecAccessControlOr | kSecAccessControlWatch; #endif + +#if XC_COMPILER_SUPPORT(TOUCH_ID) + if (isPasswordFallbackPossible()) { + accessControlFlags = accessControlFlags | kSecAccessControlOr | kSecAccessControlDevicePasscode; } +#endif SecAccessControlRef sacObject = SecAccessControlCreateWithFlags( kCFAllocatorDefault, kSecAttrAccessibleWhenUnlockedThisDeviceOnly, accessControlFlags, &error); if (sacObject == NULL || error != NULL) { NSError* e = (__bridge NSError*) error; - debug("TouchID::storeKey - Error creating security flags: %s", e.localizedDescription.UTF8String); + debug("TouchID::setKey - Error creating security flags: %s", e.localizedDescription.UTF8String); return false; } @@ -174,38 +191,49 @@ bool TouchID::storeKey(const QString& databasePath, const QByteArray& passwordKe // add to KeyChain OSStatus status = SecItemAdd(attributes, NULL); - LogStatusError("TouchID::storeKey - Status adding new entry", status); + LogStatusError("TouchID::setKey - Status adding new entry", status); CFRelease(sacObject); CFRelease(attributes); + + // Cleanse the key information from the memory + Botan::secure_scrub_memory(randomKey.data(), randomKey.size()); + Botan::secure_scrub_memory(randomIV.data(), randomIV.size()); if (status != errSecSuccess) { return false; } - // Cleanse the key information from the memory - Botan::secure_scrub_memory(randomKey.data(), randomKey.size()); - Botan::secure_scrub_memory(randomIV.data(), randomIV.size()); - // memorize which database the stored key is for - m_encryptedMasterKeys.insert(databasePath, encryptedMasterKey); - debug("TouchID::storeKey - Success!"); + m_encryptedMasterKeys.insert(dbUuid, encryptedMasterKey); + debug("TouchID::setKey - Success!"); return true; } +/** + * Generates a random AES 256bit key and uses it to encrypt the PasswordKey that + * protects the database. The encrypted PasswordKey is kept in memory while the + * AES key is stored in the macOS KeyChain protected by either TouchID or Apple Watch. + */ +bool TouchID::setKey(const QUuid& dbUuid, const QByteArray& passwordKey) +{ + if (!setKey(dbUuid,passwordKey, false)) { + debug("TouchID::setKey failed with error trying fallback method without TouchID flag"); + return setKey(dbUuid, passwordKey, true); + } else { + return true; + } +} + /** * Checks if an encrypted PasswordKey is available for the given database, tries to * decrypt it using the KeyChain and if successful, returns it. */ -bool TouchID::getKey(const QString& databasePath, QByteArray& passwordKey) const +bool TouchID::getKey(const QUuid& dbUuid, QByteArray& passwordKey) { passwordKey.clear(); - if (databasePath.isEmpty()) { - debug("TouchID::getKey - missing database path"); - return false; - } - if (!containsKey(databasePath)) { + if (!hasKey(dbUuid)) { debug("TouchID::getKey - No stored key found"); return false; } @@ -213,7 +241,7 @@ bool TouchID::getKey(const QString& databasePath, QByteArray& passwordKey) const // query the KeyChain for the AES key CFMutableDictionaryRef query = makeDictionary(); - const QString keyName = databaseKeyName(databasePath); + const QString keyName = databaseKeyName(dbUuid); NSString* accountName = keyName.toNSString(); // The NSString is released by Qt NSString* touchPromptMessage = QCoreApplication::translate("DatabaseOpenWidget", "authenticate to access the database") @@ -254,7 +282,7 @@ bool TouchID::getKey(const QString& databasePath, QByteArray& passwordKey) const } // decrypt PasswordKey from memory using AES - passwordKey = m_encryptedMasterKeys[databasePath]; + passwordKey = m_encryptedMasterKeys[dbUuid]; if (!aes256Decrypt.finish(passwordKey)) { passwordKey.clear(); debug("TouchID::getKey - AES decrypt failed: %s", aes256Decrypt.errorString().toUtf8().constData()); @@ -268,9 +296,9 @@ bool TouchID::getKey(const QString& databasePath, QByteArray& passwordKey) const return true; } -bool TouchID::containsKey(const QString& dbPath) const +bool TouchID::hasKey(const QUuid& dbUuid) const { - return m_encryptedMasterKeys.contains(dbPath); + return m_encryptedMasterKeys.contains(dbUuid); } // TODO: Both functions below should probably handle the returned errors to @@ -335,24 +363,46 @@ bool TouchID::isTouchIdAvailable() #endif } +bool TouchID::isPasswordFallbackPossible() +{ +#if XC_COMPILER_SUPPORT(TOUCH_ID) + @try { + LAContext *context = [[LAContext alloc] init]; + + LAPolicy policyCode = LAPolicyDeviceOwnerAuthentication; + NSError *error; + + bool canAuthenticate = [context canEvaluatePolicy:policyCode error:&error]; + [context release]; + if (error) { + debug("Password fallback available: %d (%ld / %s / %s)", canAuthenticate, + (long)error.code, error.description.UTF8String, + error.localizedDescription.UTF8String); + } else { + debug("Password fallback available: %d", canAuthenticate); + } + return canAuthenticate; + } @catch (NSException *) { + return false; + } +#else + return false; +#endif +} + //! @return true if either TouchID or Apple Watch is available at the moment. -bool TouchID::isAvailable() +bool TouchID::isAvailable() const { // note: we cannot cache the check results because the configuration // is dynamic in its nature. User can close the laptop lid or take off // the watch, thus making one (or both) of the authentication types unavailable. - return isWatchAvailable() || isTouchIdAvailable(); + return isWatchAvailable() || isTouchIdAvailable() || isPasswordFallbackPossible(); } /** * Resets the inner state either for all or for the given database */ -void TouchID::reset(const QString& databasePath) +void TouchID::reset(const QUuid& dbUuid) { - if (databasePath.isEmpty()) { - m_encryptedMasterKeys.clear(); - return; - } - - m_encryptedMasterKeys.remove(databasePath); + m_encryptedMasterKeys.remove(dbUuid); } diff --git a/src/winhello/WindowsHello.cpp b/src/quickunlock/WindowsHello.cpp similarity index 82% rename from src/winhello/WindowsHello.cpp rename to src/quickunlock/WindowsHello.cpp index bc244cc26..890e3499a 100644 --- a/src/winhello/WindowsHello.cpp +++ b/src/quickunlock/WindowsHello.cpp @@ -99,28 +99,10 @@ namespace } } // namespace -WindowsHello* WindowsHello::m_instance{nullptr}; -WindowsHello* WindowsHello::instance() -{ - if (!m_instance) { - m_instance = new WindowsHello(); - } - return m_instance; -} - -WindowsHello::WindowsHello(QObject* parent) - : QObject(parent) -{ - concurrency::create_task([this] { - bool state = KeyCredentialManager::IsSupportedAsync().get(); - m_available = state; - emit availableChanged(m_available); - }); -} - bool WindowsHello::isAvailable() const { - return m_available; + auto task = concurrency::create_task([] { return KeyCredentialManager::IsSupportedAsync().get(); }); + return task.get(); } QString WindowsHello::errorString() const @@ -128,7 +110,7 @@ QString WindowsHello::errorString() const return m_error; } -bool WindowsHello::storeKey(const QString& dbPath, const QByteArray& data) +bool WindowsHello::setKey(const QUuid& dbUuid, const QByteArray& data) { queueSecurityPromptFocus(); @@ -144,26 +126,26 @@ bool WindowsHello::storeKey(const QString& dbPath, const QByteArray& data) // Encrypt the data using AES-256-CBC SymmetricCipher cipher; if (!cipher.init(SymmetricCipher::Aes256_GCM, SymmetricCipher::Encrypt, key, challenge)) { - m_error = tr("Failed to init KeePassXC crypto."); + m_error = QObject::tr("Failed to init KeePassXC crypto."); return false; } QByteArray encrypted = data; if (!cipher.finish(encrypted)) { - m_error = tr("Failed to encrypt key data."); + m_error = QObject::tr("Failed to encrypt key data."); return false; } // Prepend the challenge/IV to the encrypted data encrypted.prepend(challenge); - m_encryptedKeys.insert(dbPath, encrypted); + m_encryptedKeys.insert(dbUuid, encrypted); return true; } -bool WindowsHello::getKey(const QString& dbPath, QByteArray& data) +bool WindowsHello::getKey(const QUuid& dbUuid, QByteArray& data) { data.clear(); - if (!hasKey(dbPath)) { - m_error = tr("Failed to get Windows Hello credential."); + if (!hasKey(dbUuid)) { + m_error = QObject::tr("Failed to get Windows Hello credential."); return false; } @@ -171,7 +153,7 @@ bool WindowsHello::getKey(const QString& dbPath, QByteArray& data) // Read the previously used challenge and encrypted data auto ivSize = SymmetricCipher::defaultIvSize(SymmetricCipher::Aes256_GCM); - const auto& keydata = m_encryptedKeys.value(dbPath); + const auto& keydata = m_encryptedKeys.value(dbUuid); auto challenge = keydata.left(ivSize); auto encrypted = keydata.mid(ivSize); QByteArray key; @@ -183,7 +165,7 @@ bool WindowsHello::getKey(const QString& dbPath, QByteArray& data) // Decrypt the data using the generated key and IV from above SymmetricCipher cipher; if (!cipher.init(SymmetricCipher::Aes256_GCM, SymmetricCipher::Decrypt, key, challenge)) { - m_error = tr("Failed to init KeePassXC crypto."); + m_error = QObject::tr("Failed to init KeePassXC crypto."); return false; } @@ -191,21 +173,21 @@ bool WindowsHello::getKey(const QString& dbPath, QByteArray& data) data = encrypted; if (!cipher.finish(data)) { data.clear(); - m_error = tr("Failed to decrypt key data."); + m_error = QObject::tr("Failed to decrypt key data."); return false; } return true; } -void WindowsHello::reset(const QString& dbPath) +void WindowsHello::reset(const QUuid& dbUuid) { - m_encryptedKeys.remove(dbPath); + m_encryptedKeys.remove(dbUuid); } -bool WindowsHello::hasKey(const QString& dbPath) const +bool WindowsHello::hasKey(const QUuid& dbUuid) const { - return m_encryptedKeys.contains(dbPath); + return m_encryptedKeys.contains(dbUuid); } void WindowsHello::reset() diff --git a/src/winhello/WindowsHello.h b/src/quickunlock/WindowsHello.h similarity index 57% rename from src/winhello/WindowsHello.h rename to src/quickunlock/WindowsHello.h index 5faf7eb25..9da6e4160 100644 --- a/src/winhello/WindowsHello.h +++ b/src/quickunlock/WindowsHello.h @@ -18,41 +18,28 @@ #ifndef KEEPASSXC_WINDOWSHELLO_H #define KEEPASSXC_WINDOWSHELLO_H +#include "QuickUnlockInterface.h" + #include #include -class WindowsHello : public QObject +class WindowsHello : public QuickUnlockInterface { - Q_OBJECT - public: - static WindowsHello* instance(); - bool isAvailable() const; - QString errorString() const; - void reset(); + WindowsHello() = default; + bool isAvailable() const override; + QString errorString() const override; + void reset() override; - bool storeKey(const QString& dbPath, const QByteArray& key); - bool getKey(const QString& dbPath, QByteArray& key); - bool hasKey(const QString& dbPath) const; - void reset(const QString& dbPath); - -signals: - void availableChanged(bool state); + bool setKey(const QUuid& dbUuid, const QByteArray& key) override; + bool getKey(const QUuid& dbUuid, QByteArray& key) override; + bool hasKey(const QUuid& dbUuid) const override; + void reset(const QUuid& dbUuid) override; private: - bool m_available = false; QString m_error; - QHash m_encryptedKeys; - - static WindowsHello* m_instance; - WindowsHello(QObject* parent = nullptr); - ~WindowsHello() override = default; + QHash m_encryptedKeys; Q_DISABLE_COPY(WindowsHello); }; -inline WindowsHello* getWindowsHello() -{ - return WindowsHello::instance(); -} - #endif // KEEPASSXC_WINDOWSHELLO_H diff --git a/src/quickunlock/dbus/org.freedesktop.PolicyKit1.Authority.xml b/src/quickunlock/dbus/org.freedesktop.PolicyKit1.Authority.xml new file mode 100644 index 000000000..d46d71d2a --- /dev/null +++ b/src/quickunlock/dbus/org.freedesktop.PolicyKit1.Authority.xml @@ -0,0 +1,16 @@ + + + + + + + + + > + + + + + + + diff --git a/src/sshagent/AgentSettingsWidget.cpp b/src/sshagent/AgentSettingsWidget.cpp index 1a55e14fa..bdad6e30e 100644 --- a/src/sshagent/AgentSettingsWidget.cpp +++ b/src/sshagent/AgentSettingsWidget.cpp @@ -90,9 +90,9 @@ void AgentSettingsWidget::loadSettings() void AgentSettingsWidget::saveSettings() { - auto sshAuthSockOverride = m_ui->sshAuthSockOverrideEdit->text(); + auto sshAuthSockOverride = m_ui->sshAuthSockOverrideEdit->text().trimmed(); sshAgent()->setAuthSockOverride(sshAuthSockOverride); - auto sshSecurityKeyProviderOverride = m_ui->sshSecurityKeyProviderOverrideEdit->text(); + auto sshSecurityKeyProviderOverride = m_ui->sshSecurityKeyProviderOverrideEdit->text().trimmed(); sshAgent()->setSecurityKeyProviderOverride(sshSecurityKeyProviderOverride); #ifdef Q_OS_WIN sshAgent()->setUsePageant(m_ui->usePageantRadioButton->isChecked() || m_ui->useBothRadioButton->isChecked()); diff --git a/src/sshagent/BinaryStream.cpp b/src/sshagent/BinaryStream.cpp index 3ba4c1a81..2ac93943c 100644 --- a/src/sshagent/BinaryStream.cpp +++ b/src/sshagent/BinaryStream.cpp @@ -21,14 +21,12 @@ BinaryStream::BinaryStream(QIODevice* device) : QObject(device) - , m_timeout(-1) , m_device(device) { } BinaryStream::BinaryStream(QByteArray* ba, QObject* parent) : QObject(parent) - , m_timeout(-1) { m_buffer.reset(new QBuffer(ba)); m_buffer->open(QIODevice::ReadWrite); diff --git a/src/sshagent/BinaryStream.h b/src/sshagent/BinaryStream.h index 0bc06e845..572f57427 100644 --- a/src/sshagent/BinaryStream.h +++ b/src/sshagent/BinaryStream.h @@ -55,7 +55,7 @@ protected: bool write(const char* ptr, qint64 len); private: - int m_timeout; + int m_timeout = 3000; QString m_error; QIODevice* m_device; QScopedPointer m_buffer; diff --git a/src/sshagent/CMakeLists.txt b/src/sshagent/CMakeLists.txt index 969467415..6bbb9c94d 100644 --- a/src/sshagent/CMakeLists.txt +++ b/src/sshagent/CMakeLists.txt @@ -8,6 +8,8 @@ if(WITH_XC_SSHAGENT) BinaryStream.cpp KeeAgentSettings.cpp OpenSSHKey.cpp + OpenSSHKeyGen.cpp + OpenSSHKeyGenDialog.cpp SSHAgent.cpp ) diff --git a/src/sshagent/KeeAgentSettings.cpp b/src/sshagent/KeeAgentSettings.cpp index 272fb7edf..a794eac93 100644 --- a/src/sshagent/KeeAgentSettings.cpp +++ b/src/sshagent/KeeAgentSettings.cpp @@ -490,11 +490,7 @@ bool KeeAgentSettings::toOpenSSHKey(const QString& username, } if (key.comment().isEmpty()) { - key.setComment(username); - } - - if (key.comment().isEmpty()) { - key.setComment(fileName); + key.setComment(QString("%1@%2").arg(username, fileName)); } return true; diff --git a/src/sshagent/OpenSSHKey.cpp b/src/sshagent/OpenSSHKey.cpp index e6b21c863..7df1c4287 100644 --- a/src/sshagent/OpenSSHKey.cpp +++ b/src/sshagent/OpenSSHKey.cpp @@ -20,6 +20,8 @@ #include "ASN1Key.h" #include "BinaryStream.h" +#include "core/Global.h" +#include "crypto/Random.h" #include "crypto/SymmetricCipher.h" #include @@ -34,6 +36,7 @@ const QString OpenSSHKey::OPENSSH_CIPHER_SUFFIX = "@openssh.com"; OpenSSHKey::OpenSSHKey(QObject* parent) : QObject(parent) + , m_check(0) , m_type(QString()) , m_cipherName(QString("none")) , m_kdfName(QString("none")) @@ -49,6 +52,7 @@ OpenSSHKey::OpenSSHKey(QObject* parent) OpenSSHKey::OpenSSHKey(const OpenSSHKey& other) : QObject(nullptr) + , m_check(other.m_check) , m_type(other.m_type) , m_cipherName(other.m_cipherName) , m_kdfName(other.m_kdfName) @@ -81,7 +85,7 @@ const QString OpenSSHKey::type() const const QString OpenSSHKey::fingerprint(QCryptographicHash::Algorithm algo) const { if (m_rawPublicData.isEmpty()) { - return {}; + return tr("(encrypted)"); } QByteArray publicKey; @@ -126,6 +130,64 @@ const QString OpenSSHKey::publicKey() const return m_type + " " + QString::fromLatin1(publicKey.toBase64()) + " " + m_comment; } +const QString OpenSSHKey::privateKey() +{ + QByteArray sshKey; + BinaryStream stream(&sshKey); + + // magic + stream.write(QString("openssh-key-v1").toUtf8()); + stream.write(static_cast(0)); + + // cipher name + stream.writeString(QString("none")); + + // kdf name + stream.writeString(QString("none")); + + // kdf options + stream.writeString(QString("")); + + // number of keys + stream.write(static_cast(1)); + + // string wrapped public key + QByteArray publicKey; + BinaryStream publicStream(&publicKey); + writePublic(publicStream); + stream.writeString(publicKey); + + // string wrapper private key + QByteArray privateKey; + BinaryStream privateStream(&privateKey); + + // integrity check value + privateStream.write(m_check); + privateStream.write(m_check); + + writePrivate(privateStream); + + // padding for unencrypted key + for (quint8 i = 1; i <= privateKey.size() % 8; i++) { + privateStream.write(i); + } + + stream.writeString(privateKey); + + // encode to PEM format + QString out; + out += "-----BEGIN OPENSSH PRIVATE KEY-----\n"; + + auto base64Key = QString::fromUtf8(sshKey.toBase64()); + for (int i = 0; i < base64Key.size(); i += 70) { + out += base64Key.midRef(i, 70); + out += "\n"; + } + + out += "-----END OPENSSH PRIVATE KEY-----\n"; + return out; +} + const QString OpenSSHKey::errorString() const { return m_error; @@ -136,6 +198,11 @@ void OpenSSHKey::setType(const QString& type) m_type = type; } +void OpenSSHKey::setCheck(quint32 check) +{ + m_check = check; +} + void OpenSSHKey::setPublicData(const QByteArray& data) { m_rawPublicData = data; @@ -160,7 +227,7 @@ void OpenSSHKey::clearPrivate() bool OpenSSHKey::extractPEM(const QByteArray& in, QByteArray& out) { QString pem = QString::fromLatin1(in); - QStringList rows = pem.split(QRegularExpression("(?:\r?\n|\r)"), QString::SkipEmptyParts); + QStringList rows = pem.split(QRegularExpression("(?:\r?\n|\r)"), Qt::SkipEmptyParts); if (rows.length() < 3) { m_error = tr("Invalid key file, expecting an OpenSSH key"); @@ -285,6 +352,8 @@ bool OpenSSHKey::parsePKCS1PEM(const QByteArray& in) // load private if no encryption if (!encrypted()) { return openKey(); + } else { + m_comment = tr("(encrypted)"); } return true; @@ -429,6 +498,8 @@ bool OpenSSHKey::openKey(const QString& passphrase) return false; } + m_check = checkInt1; + return readPrivate(keyStream); } diff --git a/src/sshagent/OpenSSHKey.h b/src/sshagent/OpenSSHKey.h index a42e433de..c2c831939 100644 --- a/src/sshagent/OpenSSHKey.h +++ b/src/sshagent/OpenSSHKey.h @@ -41,9 +41,11 @@ public: const QString fingerprint(QCryptographicHash::Algorithm algo = QCryptographicHash::Sha256) const; const QString comment() const; const QString publicKey() const; + const QString privateKey(); const QString errorString() const; void setType(const QString& type); + void setCheck(quint32 check); void setPublicData(const QByteArray& data); void setPrivateData(const QByteArray& data); void setComment(const QString& comment); @@ -70,6 +72,7 @@ private: bool extractPEM(const QByteArray& in, QByteArray& out); + quint32 m_check; QString m_type; QString m_cipherName; QByteArray m_cipherIV; diff --git a/src/sshagent/OpenSSHKeyGen.cpp b/src/sshagent/OpenSSHKeyGen.cpp new file mode 100644 index 000000000..a3d88807f --- /dev/null +++ b/src/sshagent/OpenSSHKeyGen.cpp @@ -0,0 +1,146 @@ +/* + * Copyright (C) 2021 KeePassXC Team + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 or (at your option) + * version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "OpenSSHKeyGen.h" +#include "BinaryStream.h" +#include "OpenSSHKey.h" +#include "config-keepassx.h" +#include "crypto/Random.h" + +#include +#include +#include + +namespace OpenSSHKeyGen +{ + namespace + { + void bigIntToStream(const Botan::BigInt& i, BinaryStream& stream, int padding = 0) + { + QByteArray ba(i.bytes() + padding, 0); + i.binary_encode(reinterpret_cast(ba.data() + padding), ba.size() - padding); + stream.writeString(ba); + } + + void vectorToStream(const std::vector& v, BinaryStream& stream) + { + QByteArray ba(reinterpret_cast(v.data()), v.size()); + stream.writeString(ba); + } + + void vectorToStream(const Botan::secure_vector& v, BinaryStream& stream) + { + QByteArray ba(reinterpret_cast(v.data()), v.size()); + stream.writeString(ba); + } + } // namespace + + bool generateRSA(OpenSSHKey& key, int bits) + { + auto rng = randomGen()->getRng(); + + try { + Botan::RSA_PrivateKey rsaKey(*rng, bits); + + QByteArray publicData; + BinaryStream publicStream(&publicData); + // intentionally flipped n e -> e n + bigIntToStream(rsaKey.get_e(), publicStream); + bigIntToStream(rsaKey.get_n(), publicStream, 1); + + QByteArray privateData; + BinaryStream privateStream(&privateData); + bigIntToStream(rsaKey.get_n(), privateStream, 1); + bigIntToStream(rsaKey.get_e(), privateStream); + bigIntToStream(rsaKey.get_d(), privateStream, 1); + bigIntToStream(rsaKey.get_c(), privateStream, 1); + bigIntToStream(rsaKey.get_p(), privateStream, 1); + bigIntToStream(rsaKey.get_q(), privateStream, 1); + + key.setType("ssh-rsa"); + key.setCheck(randomGen()->randomUInt(std::numeric_limits::max() - 1) + 1); + key.setPublicData(publicData); + key.setPrivateData(privateData); + key.setComment("id_rsa"); + return true; + } catch (std::exception& e) { + return false; + } + } + + bool generateECDSA(OpenSSHKey& key, int bits) + { + auto rng = randomGen()->getRng(); + QString group = QString("nistp%1").arg(bits); + + try { + Botan::EC_Group domain(QString("secp%1r1").arg(bits).toStdString()); + Botan::ECDSA_PrivateKey ecdsaKey(*rng, domain); + + QByteArray publicData; + BinaryStream publicStream(&publicData); + publicStream.writeString(group); + vectorToStream(ecdsaKey.public_key_bits(), publicStream); + + QByteArray privateData; + BinaryStream privateStream(&privateData); + privateStream.writeString(group); + vectorToStream(ecdsaKey.public_key_bits(), privateStream); + bigIntToStream(ecdsaKey.private_value(), privateStream, 1); + + key.setType("ecdsa-sha2-" + group); + key.setCheck(randomGen()->randomUInt(std::numeric_limits::max() - 1) + 1); + key.setPublicData(publicData); + key.setPrivateData(privateData); + key.setComment("id_ecdsa"); + return true; + } catch (std::exception& e) { + return false; + } + } + + bool generateEd25519(OpenSSHKey& key) + { + auto rng = randomGen()->getRng(); + + try { + Botan::Ed25519_PrivateKey ed25519Key(*rng); + + QByteArray publicData; + BinaryStream publicStream(&publicData); + vectorToStream(ed25519Key.get_public_key(), publicStream); + + QByteArray privateData; + BinaryStream privateStream(&privateData); + vectorToStream(ed25519Key.get_public_key(), privateStream); +#ifdef WITH_XC_BOTAN3 + vectorToStream(ed25519Key.raw_private_key_bits(), privateStream); +#else + vectorToStream(ed25519Key.get_private_key(), privateStream); +#endif + + key.setType("ssh-ed25519"); + key.setCheck(randomGen()->randomUInt(std::numeric_limits::max() - 1) + 1); + key.setPublicData(publicData); + key.setPrivateData(privateData); + key.setComment("id_ed25519"); + return true; + } catch (std::exception& e) { + return false; + } + } +} // namespace OpenSSHKeyGen diff --git a/src/sshagent/OpenSSHKeyGen.h b/src/sshagent/OpenSSHKeyGen.h new file mode 100644 index 000000000..dfe122ac0 --- /dev/null +++ b/src/sshagent/OpenSSHKeyGen.h @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2021 KeePassXC Team + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 or (at your option) + * version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef KEEPASSXC_OPENSSHKEYGEN_H +#define KEEPASSXC_OPENSSHKEYGEN_H + +class OpenSSHKey; + +namespace OpenSSHKeyGen +{ + bool generateRSA(OpenSSHKey& key, int bits); + bool generateECDSA(OpenSSHKey& key, int bits); + bool generateEd25519(OpenSSHKey& key); +} // namespace OpenSSHKeyGen + +#endif diff --git a/src/sshagent/OpenSSHKeyGenDialog.cpp b/src/sshagent/OpenSSHKeyGenDialog.cpp new file mode 100644 index 000000000..df06879e9 --- /dev/null +++ b/src/sshagent/OpenSSHKeyGenDialog.cpp @@ -0,0 +1,99 @@ +/* + * Copyright (C) 2021 KeePassXC Team + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 or (at your option) + * version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "OpenSSHKeyGenDialog.h" +#include "OpenSSHKey.h" +#include "OpenSSHKeyGen.h" +#include "gui/Icons.h" +#include "ui_OpenSSHKeyGenDialog.h" +#include +#include + +OpenSSHKeyGenDialog::OpenSSHKeyGenDialog(QWidget* parent) + : QDialog(parent) + , m_ui(new Ui::OpenSSHKeyGenDialog()) + , m_key(nullptr) +{ + setAttribute(Qt::WA_DeleteOnClose); + setWindowIcon(icons()->icon("password-generator")); + + m_ui->setupUi(this); + + m_ui->typeComboBox->clear(); + m_ui->typeComboBox->addItem("Ed25519"); + m_ui->typeComboBox->addItem("RSA"); + m_ui->typeComboBox->addItem("ECDSA"); + + QString user = QProcessEnvironment::systemEnvironment().value("USER"); + m_ui->commentLineEdit->setText(user + "@" + QHostInfo::localHostName()); + + connect(m_ui->typeComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(typeChanged())); + + typeChanged(); +} + +// Required for QScopedPointer +OpenSSHKeyGenDialog::~OpenSSHKeyGenDialog() +{ +} + +void OpenSSHKeyGenDialog::typeChanged() +{ + m_ui->bitsComboBox->clear(); + + if (m_ui->typeComboBox->currentText() == QString("Ed25519")) { + m_ui->bitsComboBox->addItem("32"); + } else if (m_ui->typeComboBox->currentText() == QString("RSA")) { + m_ui->bitsComboBox->addItem("2048"); + m_ui->bitsComboBox->addItem("3072"); + m_ui->bitsComboBox->addItem("4096"); + m_ui->bitsComboBox->setCurrentText("3072"); + } else if (m_ui->typeComboBox->currentText() == QString("ECDSA")) { + m_ui->bitsComboBox->addItem("256"); + m_ui->bitsComboBox->addItem("384"); + m_ui->bitsComboBox->addItem("521"); + m_ui->bitsComboBox->setCurrentText("256"); + } +} + +void OpenSSHKeyGenDialog::accept() +{ + // disable form and try to process this update before blocking in key generation + setEnabled(false); + QCoreApplication::processEvents(); + + int bits = m_ui->bitsComboBox->currentText().toInt(); + + if (m_ui->typeComboBox->currentText() == QString("Ed25519")) { + OpenSSHKeyGen::generateEd25519(*m_key); + } else if (m_ui->typeComboBox->currentText() == QString("RSA")) { + OpenSSHKeyGen::generateRSA(*m_key, bits); + } else if (m_ui->typeComboBox->currentText() == QString("ECDSA")) { + OpenSSHKeyGen::generateECDSA(*m_key, bits); + } else { + reject(); + return; + } + + m_key->setComment(m_ui->commentLineEdit->text()); + QDialog::accept(); +} + +void OpenSSHKeyGenDialog::setKey(OpenSSHKey* key) +{ + m_key = key; +} diff --git a/src/sshagent/OpenSSHKeyGenDialog.h b/src/sshagent/OpenSSHKeyGenDialog.h new file mode 100644 index 000000000..f46a1abe3 --- /dev/null +++ b/src/sshagent/OpenSSHKeyGenDialog.h @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2021 Team KeePassXC + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 or (at your option) + * version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef KEEPASSXC_OPENSSHKEYGENDIALOG_H +#define KEEPASSXC_OPENSSHKEYGENDIALOG_H + +#include +class OpenSSHKey; + +namespace Ui +{ + class OpenSSHKeyGenDialog; +} + +class OpenSSHKeyGenDialog : public QDialog +{ + Q_OBJECT + +public: + explicit OpenSSHKeyGenDialog(QWidget* parent = nullptr); + ~OpenSSHKeyGenDialog() override; + + void accept() override; + void setKey(OpenSSHKey* key); + +private slots: + void typeChanged(); + +private: + QScopedPointer m_ui; + OpenSSHKey* m_key; +}; + +#endif // KEEPASSXC_OPENSSHKEYGENDIALOG_H diff --git a/src/sshagent/OpenSSHKeyGenDialog.ui b/src/sshagent/OpenSSHKeyGenDialog.ui new file mode 100644 index 000000000..1f9e483dd --- /dev/null +++ b/src/sshagent/OpenSSHKeyGenDialog.ui @@ -0,0 +1,138 @@ + + + OpenSSHKeyGenDialog + + + + 0 + 0 + 200 + 100 + + + + + 0 + 0 + + + + SSH Key Generator + + + true + + + + + + + 0 + 0 + + + + QComboBox::AdjustToContents + + + + + + + + 0 + 0 + + + + Type + + + + + + + + 0 + 0 + + + + Bits + + + + + + + Comment + + + + + + + + 0 + 0 + + + + QComboBox::AdjustToContents + + + 4 + + + + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + + + buttonBox + accepted() + OpenSSHKeyGenDialog + accept() + + + 248 + 254 + + + 157 + 274 + + + + + buttonBox + rejected() + OpenSSHKeyGenDialog + reject() + + + 316 + 260 + + + 286 + 274 + + + + + diff --git a/src/sshagent/SSHAgent.cpp b/src/sshagent/SSHAgent.cpp index d3da08323..a8aa695ce 100644 --- a/src/sshagent/SSHAgent.cpp +++ b/src/sshagent/SSHAgent.cpp @@ -363,6 +363,48 @@ bool SSHAgent::removeIdentity(OpenSSHKey& key) return sendMessage(requestData, responseData); } +/** + * Remove all identities from the SSH agent. + * + * Since the agent might be forwarded, old or non-OpenSSH, when asked + * to remove all keys, attempt to remove both protocol v.1 and v.2 + * keys. + * + * @return true on success + */ +bool SSHAgent::clearAllAgentIdentities() +{ + if (!isAgentRunning()) { + m_error = tr("No agent running, cannot remove identity."); + return false; + } + + bool ret = true; + QByteArray requestData; + QByteArray responseData; + BinaryStream request(&requestData); + + // SSH2 Identity Removal + request.write(SSH2_AGENTC_REMOVE_ALL_IDENTITIES); + + if (!sendMessage(requestData, responseData)) { + m_error = tr("Failed to remove all SSH identities from agent."); + ret = false; + } + + request.flush(); + responseData.clear(); + + // SSH1 Identity Removal + request.write(SSH_AGENTC_REMOVE_ALL_RSA_IDENTITIES); + + // ignore error-code for ssh1 + sendMessage(requestData, responseData); + + m_error = tr("All SSH identities removed from agent."); + return ret; +} + /** * Get a list of identities from the SSH agent. * @@ -433,7 +475,7 @@ bool SSHAgent::listIdentities(QList>& list) * Check if this identity is loaded in the SSH Agent. * * @param key identity to remove - * @param loaded is the key laoded + * @param loaded is the key loaded * @return true on success */ bool SSHAgent::checkIdentity(const OpenSSHKey& key, bool& loaded) diff --git a/src/sshagent/SSHAgent.h b/src/sshagent/SSHAgent.h index 8ef6173a6..d3eeb4ebc 100644 --- a/src/sshagent/SSHAgent.h +++ b/src/sshagent/SSHAgent.h @@ -56,6 +56,7 @@ public: bool checkIdentity(const OpenSSHKey& key, bool& loaded); bool removeIdentity(OpenSSHKey& key); void removeAllIdentities(); + bool clearAllAgentIdentities(); void setAutoRemoveOnLock(const OpenSSHKey& key, bool autoRemove); signals: @@ -74,6 +75,8 @@ private: const quint8 SSH_AGENTC_ADD_IDENTITY = 17; const quint8 SSH_AGENTC_REMOVE_IDENTITY = 18; const quint8 SSH_AGENTC_ADD_ID_CONSTRAINED = 25; + const quint8 SSH_AGENTC_REMOVE_ALL_RSA_IDENTITIES = 9; + const quint8 SSH2_AGENTC_REMOVE_ALL_IDENTITIES = 19; const quint8 SSH_AGENT_CONSTRAIN_LIFETIME = 1; const quint8 SSH_AGENT_CONSTRAIN_CONFIRM = 2; diff --git a/src/streams/HashedBlockStream.cpp b/src/streams/HashedBlockStream.cpp index 7cc25d1ea..d04b42dfb 100644 --- a/src/streams/HashedBlockStream.cpp +++ b/src/streams/HashedBlockStream.cpp @@ -126,7 +126,7 @@ bool HashedBlockStream::readHashedBlock() { bool ok; - quint32 index = Endian::readSizedInt(m_baseDevice, ByteOrder, &ok); + auto index = Endian::readSizedInt(m_baseDevice, ByteOrder, &ok); if (!ok || index != m_blockIndex) { m_error = true; setErrorString("Invalid block index."); diff --git a/src/streams/HashedBlockStream.h b/src/streams/HashedBlockStream.h index e107c2cce..dc1c16a1a 100644 --- a/src/streams/HashedBlockStream.h +++ b/src/streams/HashedBlockStream.h @@ -29,7 +29,7 @@ class HashedBlockStream : public LayeredStream public: explicit HashedBlockStream(QIODevice* baseDevice); HashedBlockStream(QIODevice* baseDevice, qint32 blockSize); - ~HashedBlockStream(); + ~HashedBlockStream() override; bool reset() override; void close() override; diff --git a/src/streams/HashingStream.cpp b/src/streams/HashingStream.cpp new file mode 100644 index 000000000..5139dae87 --- /dev/null +++ b/src/streams/HashingStream.cpp @@ -0,0 +1,101 @@ +/* + * Copyright (C) 2024 KeePassXC Team + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 or (at your option) + * version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "HashingStream.h" + +HashingStream::HashingStream(QIODevice* baseDevice) + : LayeredStream(baseDevice) + , m_hash(QCryptographicHash::Md5) + , m_sizeToHash(0) +{ + init(); +} + +HashingStream::HashingStream(QIODevice* baseDevice, QCryptographicHash::Algorithm hashAlgo, qint64 sizeToHash) + : LayeredStream(baseDevice) + , m_hash(hashAlgo) + , m_sizeToHash(sizeToHash) +{ + init(); +} + +HashingStream::~HashingStream() +{ + close(); +} + +void HashingStream::init() +{ + m_sizeHashed = 0; + m_sizeStreamed = 0; + m_hashFinalized = false; +} + +bool HashingStream::reset() +{ + init(); + m_hash.reset(); + return LayeredStream::reset(); +} + +QByteArray HashingStream::hashingResult() +{ + if (m_sizeHashed <= 0 || (m_sizeToHash > 0 && m_sizeHashed != m_sizeToHash)) { + setErrorString("Not enough data to compute hash"); + return {}; + } + m_hashFinalized = true; + return m_hash.result(); +} + +qint64 HashingStream::readData(char* data, qint64 maxSize) +{ + auto sizeRead = LayeredStream::readData(data, maxSize); + if (sizeRead > 0) { + if (!m_hashFinalized) { + qint64 sizeToHash = sizeRead; + if (m_sizeToHash > 0) { + sizeToHash = qMin(m_sizeToHash - m_sizeStreamed, sizeRead); + } + if (sizeToHash > 0) { + m_hash.addData(data, sizeToHash); + m_sizeHashed += sizeToHash; + } + } + m_sizeStreamed += sizeRead; + } + return sizeRead; +} + +qint64 HashingStream::writeData(const char* data, qint64 maxSize) +{ + auto sizeWritten = LayeredStream::writeData(data, maxSize); + if (sizeWritten > 0) { + if (!m_hashFinalized) { + qint64 sizeToHash = sizeWritten; + if (m_sizeToHash > 0) { + sizeToHash = qMin(m_sizeToHash - m_sizeStreamed, sizeWritten); + } + if (sizeToHash > 0) { + m_hash.addData(data, sizeToHash); + m_sizeHashed += sizeToHash; + } + } + m_sizeStreamed += sizeWritten; + } + return sizeWritten; +} diff --git a/src/streams/HashingStream.h b/src/streams/HashingStream.h new file mode 100644 index 000000000..f35374728 --- /dev/null +++ b/src/streams/HashingStream.h @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2024 KeePassXC Team + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 or (at your option) + * version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef KEEPASSX_HASHINGSTREAM_H +#define KEEPASSX_HASHINGSTREAM_H + +#include + +#include "streams/LayeredStream.h" + +class HashingStream : public LayeredStream +{ + Q_OBJECT + +public: + explicit HashingStream(QIODevice* baseDevice); + HashingStream(QIODevice* baseDevice, QCryptographicHash::Algorithm hashAlgo, qint64 sizeToHash); + ~HashingStream() override; + + bool reset() override; + + QByteArray hashingResult(); + +protected: + void init(); + + qint64 readData(char* data, qint64 maxSize) override; + qint64 writeData(const char* data, qint64 maxSize) override; + +protected: + QCryptographicHash m_hash; + bool m_hashFinalized; + qint64 m_sizeToHash; + qint64 m_sizeHashed; + qint64 m_sizeStreamed; +}; + +#endif // KEEPASSX_HASHINGSTREAM_H diff --git a/src/streams/HmacBlockStream.h b/src/streams/HmacBlockStream.h index 18f5e5301..691aa1e16 100644 --- a/src/streams/HmacBlockStream.h +++ b/src/streams/HmacBlockStream.h @@ -29,7 +29,7 @@ class HmacBlockStream : public LayeredStream public: explicit HmacBlockStream(QIODevice* baseDevice, QByteArray key); HmacBlockStream(QIODevice* baseDevice, QByteArray key, qint32 blockSize); - ~HmacBlockStream(); + ~HmacBlockStream() override; bool reset() override; void close() override; diff --git a/src/streams/LayeredStream.h b/src/streams/LayeredStream.h index 0e1156d70..643ddfb45 100644 --- a/src/streams/LayeredStream.h +++ b/src/streams/LayeredStream.h @@ -26,7 +26,7 @@ class LayeredStream : public QIODevice public: explicit LayeredStream(QIODevice* baseDevice); - virtual ~LayeredStream(); + ~LayeredStream() override; bool isSequential() const override; bool open(QIODevice::OpenMode mode) override; diff --git a/src/streams/SymmetricCipherStream.h b/src/streams/SymmetricCipherStream.h index 3f11dc8bd..10c6e4774 100644 --- a/src/streams/SymmetricCipherStream.h +++ b/src/streams/SymmetricCipherStream.h @@ -30,7 +30,7 @@ class SymmetricCipherStream : public LayeredStream public: SymmetricCipherStream(QIODevice* baseDevice); - ~SymmetricCipherStream(); + ~SymmetricCipherStream() override; bool init(SymmetricCipher::Mode mode, SymmetricCipher::Direction direction, const QByteArray& key, const QByteArray& iv); bool open(QIODevice::OpenMode mode) override; diff --git a/src/streams/qtiocompressor.h b/src/streams/qtiocompressor.h index cebd98293..458b2991d 100644 --- a/src/streams/qtiocompressor.h +++ b/src/streams/qtiocompressor.h @@ -56,18 +56,20 @@ Q_OBJECT public: enum StreamFormat { ZlibFormat, GzipFormat, RawZipFormat }; QtIOCompressor(QIODevice *device, int compressionLevel = 6, int bufferSize = 65500); - ~QtIOCompressor(); + ~QtIOCompressor() override; void setStreamFormat(StreamFormat format); StreamFormat streamFormat() const; static bool isGzipSupported(); - bool isSequential() const; - bool open(OpenMode mode); - void close(); + bool isSequential() const override; + bool open(OpenMode mode) override; + void close() override; void flush(); - qint64 bytesAvailable() const; + qint64 bytesAvailable() const override; + protected: - qint64 readData(char * data, qint64 maxSize); - qint64 writeData(const char * data, qint64 maxSize); + qint64 readData(char* data, qint64 maxSize) override; + qint64 writeData(const char* data, qint64 maxSize) override; + private: static bool checkGzipSupport(const char * const versionString); QtIOCompressorPrivate *d_ptr; diff --git a/src/thirdparty/ykcore/CMakeLists.txt b/src/thirdparty/ykcore/CMakeLists.txt index 103349f22..ecf3ab2b2 100644 --- a/src/thirdparty/ykcore/CMakeLists.txt +++ b/src/thirdparty/ykcore/CMakeLists.txt @@ -40,5 +40,5 @@ elseif(UNIX AND NOT APPLE) target_compile_definitions(ykcore PRIVATE _GNU_SOURCE) elseif(APPLE) target_sources(ykcore PRIVATE ykcore_osx.c) - target_link_libraries(ykcore PUBLIC "-framework IOKit") + target_link_libraries(ykcore PUBLIC "-framework IOKit -framework Foundation") endif() diff --git a/src/thirdparty/ykcore/ykcore.c b/src/thirdparty/ykcore/ykcore.c index cfab2425a..c4fc4f4d4 100644 --- a/src/thirdparty/ykcore/ykcore.c +++ b/src/thirdparty/ykcore/ykcore.c @@ -155,7 +155,7 @@ int yk_get_status(YK_KEY *k, YK_STATUS *status) } /* Read the factory programmed serial number from a YubiKey. - * The possibility to retreive the serial number might be disabled + * The possibility to retrieve the serial number might be disabled * using configuration, so it should not be considered a fatal error * to not be able to read the serial number using this function. * diff --git a/src/thirdparty/ykcore/ykcore.h b/src/thirdparty/ykcore/ykcore.h index 37e34e1f3..e0f3db5e3 100644 --- a/src/thirdparty/ykcore/ykcore.h +++ b/src/thirdparty/ykcore/ykcore.h @@ -78,7 +78,7 @@ extern int yk_release(void); * Functions to get and release the key itself. * ****/ -/* opens first key available. For backwards compatability */ +/* opens first key available. For backwards compatibility */ extern YK_KEY *yk_open_first_key(void); extern YK_KEY *yk_open_key(int); /* opens nth key available */ extern YK_KEY *yk_open_key_vid_pid(const int*, size_t, const int*, size_t, int); @@ -147,7 +147,7 @@ int yk_write_device_info(YK_KEY *yk, unsigned char *buf, unsigned int len); /************************************************************************* * - * Error handling fuctions + * Error handling functions * ****/ extern int * _yk_errno_location(void); diff --git a/src/thirdparty/ykcore/ykcore_lcl.h b/src/thirdparty/ykcore/ykcore_lcl.h index 53619acb9..783c1bfff 100644 --- a/src/thirdparty/ykcore/ykcore_lcl.h +++ b/src/thirdparty/ykcore/ykcore_lcl.h @@ -48,7 +48,7 @@ ** ** = = = = = = = = = B I G F A T W A R N I N G = = = = = = = = = ** - ** DO NOT USE THE FOLLOWING FUCTIONS DIRECTLY UNLESS YOU WRITE CORE ROUTINES! + ** DO NOT USE THE FOLLOWING FUNCTIONS DIRECTLY UNLESS YOU WRITE CORE ROUTINES! ** ** These functions are declared here only to make sure they get defined ** correctly internally. diff --git a/src/thirdparty/ykcore/ykdef.h b/src/thirdparty/ykcore/ykdef.h index b645dd996..80cdce6c9 100644 --- a/src/thirdparty/ykcore/ykdef.h +++ b/src/thirdparty/ykcore/ykdef.h @@ -146,7 +146,7 @@ struct config_st { /* Yubikey 2 and above */ #define CFGFLAG_SHORT_TICKET 0x02 /* Send truncated ticket (half length) */ #define CFGFLAG_STRONG_PW1 0x10 /* Strong password policy flag #1 (mixed case) */ -#define CFGFLAG_STRONG_PW2 0x40 /* Strong password policy flag #2 (subtitute 0..7 to digits) */ +#define CFGFLAG_STRONG_PW2 0x40 /* Strong password policy flag #2 (substitute 0..7 to digits) */ #define CFGFLAG_MAN_UPDATE 0x80 /* Allow manual (local) update of static OTP */ /* Yubikey 2.1 and above */ @@ -299,7 +299,7 @@ struct status_st { #define YK4_CAPA_TAG 0x01 /* TAG for capabilities */ #define YK4_SERIAL_TAG 0x02 /* TAG for serial number */ -#define YK4_CAPA1_OTP 0x01 /* Capability bit for OTP functonality */ +#define YK4_CAPA1_OTP 0x01 /* Capability bit for OTP functionality */ #define YK4_CAPA1_U2F 0x02 /* Capability bit for U2F functionality */ #define YK4_CAPA1_CCID 0x04 /* Capability bit for CCID functionality */ #define YK4_CAPA1_OPGP 0x08 /* Capability bit for OpenPGP functionality */ diff --git a/src/thirdparty/zxcvbn/CMakeLists.txt b/src/thirdparty/zxcvbn/CMakeLists.txt new file mode 100644 index 000000000..dcc2a5efd --- /dev/null +++ b/src/thirdparty/zxcvbn/CMakeLists.txt @@ -0,0 +1,9 @@ +add_library(zxcvbn STATIC zxcvbn.c) +# Disable error-level shadow issues +if(CC_HAS_Wshadow_compatible_local) + set_property(SOURCE zxcvbn.c APPEND PROPERTY COMPILE_OPTIONS "-Wno-shadow-compatible-local") +endif() +if(CC_HAS_Wshadow_local) + set_property(SOURCE zxcvbn.c APPEND PROPERTY COMPILE_OPTIONS "-Wno-shadow-local") +endif() +target_include_directories(zxcvbn PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) diff --git a/src/zxcvbn/dict-src.h b/src/thirdparty/zxcvbn/dict-src.h similarity index 100% rename from src/zxcvbn/dict-src.h rename to src/thirdparty/zxcvbn/dict-src.h diff --git a/src/zxcvbn/zxcvbn.c b/src/thirdparty/zxcvbn/zxcvbn.c similarity index 99% rename from src/zxcvbn/zxcvbn.c rename to src/thirdparty/zxcvbn/zxcvbn.c index 23792b4d6..28d53af22 100644 --- a/src/zxcvbn/zxcvbn.c +++ b/src/thirdparty/zxcvbn/zxcvbn.c @@ -60,7 +60,7 @@ /* Additional entropy to add when password is made of multiple matches. Use different * amounts depending on whether the match is at the end of the password, or in the - * middle. If the match is at the begining then there is no additional entropy. + * middle. If the match is at the beginning then there is no additional entropy. */ #define MULTI_END_ADDITION 1.0 #define MULTI_MID_ADDITION 1.75 @@ -169,7 +169,7 @@ static ZxcMatch_t *AllocMatch() static void AddResult(ZxcMatch_t **HeadRef, ZxcMatch_t *Nu, int MaxLen) { /* Adjust the entropy to be used for calculations depending on whether the passed match is - * at the begining, middle or end of the password + * at the beginning, middle or end of the password */ if (Nu->Begin) { @@ -546,7 +546,7 @@ static void AddLeetChr(uint8_t c, int IsLeet, uint8_t *Leeted, uint8_t *UnLeet) /********************************************************************************** * Given details of a word match, update it with the entropy (as natural log of - * number of possiblities) + * number of possibilities) */ static void DictionaryEntropy(ZxcMatch_t *m, DictMatchInfo_t *Extra, const uint8_t *Pwd) { @@ -1244,7 +1244,7 @@ static const char *Formats[] = 0 }; /* Possible separator characters that could be used */ -static const char DateSeperators[] = "/\\-_. "; +static const char DateSeparators[] = "/\\-_. "; /********************************************************************************** * Try to match the password with the formats above. @@ -1273,7 +1273,7 @@ static void DateMatch(ZxcMatch_t **Result, const uint8_t *Passwd, int Start, int { if (*Fmt == '?') { - if (!Sep && strchr(DateSeperators, *p)) + if (!Sep && strchr(DateSeparators, *p)) Sep = *p; Fail = (*p != Sep); } @@ -1370,7 +1370,7 @@ static void RepeatMatch(ZxcMatch_t **Result, const uint8_t *Passwd, int Start, i int Len, i; uint8_t c; Passwd += Start; - /* Remember first char and the count its occurances */ + /* Remember first char and the count its occurrences */ c = *Passwd; for(Len = 1; (Len < MaxLen) && (c == Passwd[Len]); ++Len) { } @@ -1533,9 +1533,9 @@ static void SequenceMatch(ZxcMatch_t **Result, const uint8_t *Passwd, int Start, /********************************************************************************** * Matching a password is treated as a problem of finding the minimum distance - * between two vertexes in a graph. This is solved using Dijkstra's algorithm. + * between two vertices in a graph. This is solved using Dijkstra's algorithm. * - * There are a series of nodes (or vertexes in graph terminology) which correspond + * There are a series of nodes (or vertices in graph terminology) which correspond * to points between each character of the password. Also there is a start node * before the first character and an end node after the last character. * @@ -1546,7 +1546,7 @@ static void SequenceMatch(ZxcMatch_t **Result, const uint8_t *Passwd, int Start, * end node. * * Dijkstra's algorithm finds the combination of these part matches (or paths) - * which gives the lowest entropy (or smallest distance) from begining to end + * which gives the lowest entropy (or smallest distance) from beginning to end * of the password. */ diff --git a/src/zxcvbn/zxcvbn.h b/src/thirdparty/zxcvbn/zxcvbn.h similarity index 95% rename from src/zxcvbn/zxcvbn.h rename to src/thirdparty/zxcvbn/zxcvbn.h index 9500c7a95..550680505 100644 --- a/src/zxcvbn/zxcvbn.h +++ b/src/thirdparty/zxcvbn/zxcvbn.h @@ -68,7 +68,7 @@ typedef enum /* Linked list of information returned in the Info arg to ZxcvbnMatch */ struct ZxcMatch { - int Begin; /* Char position of begining of match */ + int Begin; /* Char position of beginning of match */ int Length; /* Number of chars in the match */ double Entrpy; /* The entropy of the match */ double MltEnpy; /* Entropy with additional allowance for multipart password */ @@ -85,13 +85,13 @@ extern "C" { #ifdef USE_DICT_FILE /********************************************************************************** - * Read the dictionnary data from the given file. Returns 1 if OK, 0 if error. + * Read the dictionary data from the given file. Returns 1 if OK, 0 if error. * Called once at program startup. */ int ZxcvbnInit(const char *); /********************************************************************************** - * Free the dictionnary data after use. Called once at program shutdown. + * Free the dictionary data after use. Called once at program shutdown. */ void ZxcvbnUnInit(); @@ -107,7 +107,7 @@ void ZxcvbnUnInit(); * The main password matching function. May be called multiple times. * The parameters are: * Passwd The password to be tested. Null terminated string. - * UserDict User supplied dictionary words to be considered particulary bad. Passed + * UserDict User supplied dictionary words to be considered particularly bad. Passed * as a pointer to array of string pointers, with null last entry (like * the argv parameter to main()). May be null or point to empty array when * there are no user dictionary words. diff --git a/src/touchid/TouchID.h b/src/touchid/TouchID.h deleted file mode 100644 index e32f1fa12..000000000 --- a/src/touchid/TouchID.h +++ /dev/null @@ -1,39 +0,0 @@ -#ifndef KEEPASSX_TOUCHID_H -#define KEEPASSX_TOUCHID_H - -#include - -class TouchID -{ -public: - static TouchID& getInstance(); - -private: - TouchID() - { - // Nothing to do here - } - -public: - TouchID(TouchID const&) = delete; - void operator=(TouchID const&) = delete; - - bool storeKey(const QString& databasePath, const QByteArray& passwordKey); - bool getKey(const QString& databasePath, QByteArray& passwordKey) const; - bool containsKey(const QString& databasePath) const; - void reset(const QString& databasePath = ""); - - bool isAvailable(); - -private: - static bool isWatchAvailable(); - static bool isTouchIdAvailable(); - - static void deleteKeyEntry(const QString& accountName); - static QString databaseKeyName(const QString& databasePath); - -private: - QHash m_encryptedMasterKeys; -}; - -#endif // KEEPASSX_TOUCHID_H diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 2285995b5..25b116d8e 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -75,6 +75,8 @@ macro(add_unit_test) add_test(${_test_NAME} ${_test_LAUNCHER} ${_test_NAME}) endif(KDE4_TEST_OUTPUT STREQUAL "xml") + set_tests_properties(${_test_NAME} PROPERTIES ENVIRONMENT "LANG=en_US.UTF-8") + if(NOT MSVC_IDE) #not needed for the ide # if the tests are EXCLUDE_FROM_ALL, add a target "buildtests" to build all tests if(NOT WITH_TESTS) @@ -88,7 +90,7 @@ macro(add_unit_test) endif() endmacro(add_unit_test) -set(TEST_LIBRARIES keepassx_core Qt5::Test) +set(TEST_LIBRARIES keepassxc_gui Qt5::Test) set(testsupport_SOURCES modeltest.cpp @@ -141,7 +143,7 @@ add_unit_test(NAME testkeepass1reader SOURCES TestKeePass1Reader.cpp LIBS ${TEST_LIBRARIES}) add_unit_test(NAME testimports SOURCES TestImports.cpp - LIBS ${TEST_LIBRARIES}) + LIBS ${TEST_LIBRARIES}) if(WITH_XC_NETWORKING) add_unit_test(NAME testupdatecheck SOURCES TestUpdateCheck.cpp @@ -152,16 +154,16 @@ endif() if(WITH_XC_AUTOTYPE) add_unit_test(NAME testautotype SOURCES TestAutoType.cpp - LIBS ${TEST_LIBRARIES}) + LIBS testsupport ${TEST_LIBRARIES}) set_target_properties(testautotype PROPERTIES ENABLE_EXPORTS ON) endif() if(WITH_XC_SSHAGENT) add_unit_test(NAME testopensshkey SOURCES TestOpenSSHKey.cpp - LIBS sshagent ${TEST_LIBRARIES}) + LIBS sshagent testsupport ${TEST_LIBRARIES}) if(NOT WIN32) add_unit_test(NAME testsshagent SOURCES TestSSHAgent.cpp - LIBS ${TEST_LIBRARIES}) + LIBS sshagent testsupport ${TEST_LIBRARIES}) endif() endif() @@ -193,7 +195,7 @@ add_unit_test(NAME testcsvparser SOURCES TestCsvParser.cpp LIBS ${TEST_LIBRARIES}) add_unit_test(NAME testrandomgenerator SOURCES TestRandomGenerator.cpp - LIBS testsupport ${TEST_LIBRARIES}) + LIBS testsupport ${TEST_LIBRARIES}) add_unit_test(NAME testentrysearcher SOURCES TestEntrySearcher.cpp LIBS ${TEST_LIBRARIES}) @@ -223,22 +225,16 @@ add_unit_test(NAME testconfig SOURCES TestConfig.cpp if(WITH_XC_FDOSECRETS) add_unit_test(NAME testfdosecrets SOURCES TestFdoSecrets.cpp - LIBS testsupport ${TEST_LIBRARIES}) + LIBS testsupport fdosecrets ${TEST_LIBRARIES}) endif() if(WITH_XC_BROWSER) add_unit_test(NAME testbrowser SOURCES TestBrowser.cpp - LIBS ${TEST_LIBRARIES}) + LIBS browser ${TEST_LIBRARIES}) if(WITH_XC_BROWSER_PASSKEYS) - # Prevent duplicate linking with macOS - if(APPLE) - add_unit_test(NAME testpasskeys SOURCES TestPasskeys.cpp - LIBS ${TEST_LIBRARIES}) - else() - add_unit_test(NAME testpasskeys SOURCES TestPasskeys.cpp - LIBS keepassxcbrowser ${TEST_LIBRARIES}) - endif() + add_unit_test(NAME testpasskeys SOURCES TestPasskeys.cpp + LIBS browser ${TEST_LIBRARIES}) endif() endif() @@ -247,7 +243,7 @@ if(WITH_XC_NETWORKING OR WITH_XC_BROWSER) endif() add_unit_test(NAME testcli SOURCES TestCli.cpp - LIBS testsupport cli ${TEST_LIBRARIES}) + LIBS testsupport cli ${ZXCVBN_LIBRARIES} ${TEST_LIBRARIES}) target_compile_definitions(testcli PRIVATE KEEPASSX_CLI_PATH="$") if(WITH_GUI_TESTS) diff --git a/tests/TestAutoType.cpp b/tests/TestAutoType.cpp index eea1f0532..91bd7d0a4 100644 --- a/tests/TestAutoType.cpp +++ b/tests/TestAutoType.cpp @@ -30,13 +30,15 @@ #include "crypto/Crypto.h" #include "gui/MessageBox.h" #include "gui/osutils/OSUtils.h" +#include "util/TemporaryFile.h" QTEST_GUILESS_MAIN(TestAutoType) void TestAutoType::initTestCase() { QVERIFY(Crypto::init()); - Config::createTempFileInstance(); + // Create temporary config file + Config::createConfigFromFile(TemporaryFile::createTempConfigFile(), {}); config()->set(Config::AutoTypeDelay, 1); config()->set(Config::Security_AutoTypeAsk, false); AutoType::createTestInstance(); diff --git a/tests/TestBrowser.cpp b/tests/TestBrowser.cpp index 19dbba8f4..a2610748a 100644 --- a/tests/TestBrowser.cpp +++ b/tests/TestBrowser.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2023 KeePassXC Team + * Copyright (C) 2025 KeePassXC Team * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -170,26 +170,22 @@ void TestBrowser::testSortPriority_data() QTest::newRow("Exact Match") << siteUrl << siteUrl << siteUrl << 100; QTest::newRow("Exact Match (site)") << siteUrl << siteUrl << formUrl << 100; QTest::newRow("Exact Match (form)") << siteUrl << "https://github.net" << siteUrl << 100; - QTest::newRow("Exact Match No Trailing Slash") << "https://github.com" - << "https://github.com/" << formUrl << 100; + QTest::newRow("Exact Match No Trailing Slash") << "https://github.com" << "https://github.com/" << formUrl << 100; QTest::newRow("Exact Match No Scheme") << "github.com/login" << siteUrl << formUrl << 100; - QTest::newRow("Exact Match with Query") << "https://github.com/login?test=test#fragment" - << "https://github.com/login?test=test" << formUrl << 100; + QTest::newRow("Exact Match with Query") + << "https://github.com/login?test=test#fragment" << "https://github.com/login?test=test" << formUrl << 100; QTest::newRow("Site Query Mismatch") << siteUrl << siteUrl + "?test=test" << formUrl << 90; QTest::newRow("Path Mismatch (site)") << "https://github.com/" << siteUrl << formUrl << 85; QTest::newRow("Path Mismatch (site) No Scheme") << "github.com" << siteUrl << formUrl << 85; - QTest::newRow("Path Mismatch (form)") << "https://github.com/" - << "https://github.net" << formUrl << 85; + QTest::newRow("Path Mismatch (form)") << "https://github.com/" << "https://github.net" << formUrl << 85; QTest::newRow("Path Mismatch (diff parent)") << "https://github.com/keepassxreboot" << siteUrl << formUrl << 80; - QTest::newRow("Path Mismatch (diff parent, form)") << "https://github.com/keepassxreboot" - << "https://github.net" << formUrl << 70; + QTest::newRow("Path Mismatch (diff parent, form)") + << "https://github.com/keepassxreboot" << "https://github.net" << formUrl << 70; - QTest::newRow("Subdomain Mismatch (site)") << siteUrl << "https://sub.github.com/" - << "https://github.net/" << 60; - QTest::newRow("Subdomain Mismatch (form)") << siteUrl << "https://github.net/" - << "https://sub.github.com/" << 50; + QTest::newRow("Subdomain Mismatch (site)") << siteUrl << "https://sub.github.com/" << "https://github.net/" << 60; + QTest::newRow("Subdomain Mismatch (form)") << siteUrl << "https://github.net/" << "https://sub.github.com/" << 50; QTest::newRow("Scheme Mismatch") << "http://github.com" << siteUrl << formUrl << 0; QTest::newRow("Scheme Mismatch w/path") << "http://github.com/login" << siteUrl << formUrl << 0; @@ -226,7 +222,7 @@ void TestBrowser::testSearchEntries() QCOMPARE(result[4]->url(), QString("http://github.com")); QCOMPARE(result[5]->url(), QString("http://github.com/login")); - // With matching there should be only 3 results + 4 without a scheme + // With matching there should be only 4 results + 4 without a scheme browserSettings()->setMatchUrlScheme(true); result = m_browserService->searchEntries(db, "https://github.com", "https://github.com/session"); QCOMPARE(result.length(), 7); @@ -400,6 +396,120 @@ void TestBrowser::testSearchEntriesWithAdditionalURLs() QCOMPARE(additionalResult[0]->url(), QString("https://github.com/")); } +void TestBrowser::testSearchEntriesWithWildcardURLs() +{ + auto db = QSharedPointer::create(); + auto* root = db->rootGroup(); + + QStringList urls = { + "https://github.com/login_page/*", + "https://github.com/*/second", + "https://github.com/*", + "http://github.com/*", + "github.com/*", // Defaults to https + "https://*.github.com/*", + "https://subdomain.*.github.com/*/second", + "https://*.sub.github.com/*", + "https://********", // Invalid wildcard URL + "https://*.thub.com/", // Partial suffix URL + "https://subdomain.yes.github.com/*", + "https://example.com:8448/*", + "https://example.com/*/*", + "https://example.com/$/*", + "https://127.128.129.*:8448/", + "https://127.128.*/", + "https://127.160.*.2/login", + "http://[2001:db8:85a3:8d3:1319:8a2e:370:*]/", + "https://[2001:db8:85a3:8d3:*]:443/", + "fe80::1ff:fe23:4567:890a", + "2001-db8-85a3-8d3-1319-8a2e-370-7348.ipv6-literal.net", + "\"https://thisisatest.com/login.php\"" // Exact URL + }; + + createEntries(urls, root, true); + browserSettings()->setMatchUrlScheme(false); + + // Return first Additional URL + auto firstUrl = [&](Entry* entry) { return entry->attributes()->value(EntryAttributes::AdditionalUrlAttribute); }; + + auto result = m_browserService->searchEntries( + db, "https://github.com/login_page/second", "https://github.com/login_page/second"); + QCOMPARE(result.length(), 5); + QCOMPARE(firstUrl(result[0]), QString("https://github.com/login_page/*")); + QCOMPARE(firstUrl(result[1]), QString("https://github.com/*/second")); + QCOMPARE(firstUrl(result[2]), QString("https://github.com/*")); + QCOMPARE(firstUrl(result[3]), QString("http://github.com/*")); + QCOMPARE(firstUrl(result[4]), QString("github.com/*")); + + result = m_browserService->searchEntries( + db, "https://subdomain.sub.github.com/login_page/second", "https://subdomain.sub.github.com/login_page/second"); + QCOMPARE(result.length(), 3); + QCOMPARE(firstUrl(result[0]), QString("https://*.github.com/*")); + QCOMPARE(firstUrl(result[1]), QString("https://subdomain.*.github.com/*/second")); + QCOMPARE(firstUrl(result[2]), QString("https://*.sub.github.com/*")); + + result = m_browserService->searchEntries( + db, "https://subdomain.sub.github.com/other_page", "https://subdomain.sub.github.com/other_page"); + QCOMPARE(result.length(), 2); + QCOMPARE(firstUrl(result[0]), QString("https://*.github.com/*")); + QCOMPARE(firstUrl(result[1]), QString("https://*.sub.github.com/*")); + + result = m_browserService->searchEntries( + db, "https://subdomain.yes.github.com/other_page/second", "https://subdomain.yes.github.com/other_page/second"); + QCOMPARE(result.length(), 3); + QCOMPARE(firstUrl(result[0]), QString("https://*.github.com/*")); + QCOMPARE(firstUrl(result[1]), QString("https://subdomain.*.github.com/*/second")); + QCOMPARE(firstUrl(result[2]), QString("https://subdomain.yes.github.com/*")); + + result = m_browserService->searchEntries( + db, "https://example.com:8448/login/page", "https://example.com:8448/login/page"); + QCOMPARE(result.length(), 2); + QCOMPARE(firstUrl(result[0]), QString("https://example.com:8448/*")); + QCOMPARE(firstUrl(result[1]), QString("https://example.com/*/*")); + + result = m_browserService->searchEntries( + db, "https://example.com:8449/login/page", "https://example.com:8449/login/page"); + QCOMPARE(result.length(), 1); + QCOMPARE(firstUrl(result[0]), QString("https://example.com/*/*")); + + result = + m_browserService->searchEntries(db, "https://example.com/$/login_page", "https://example.com/$/login_page"); + QCOMPARE(result.length(), 2); + QCOMPARE(firstUrl(result[0]), QString("https://example.com/*/*")); + QCOMPARE(firstUrl(result[1]), QString("https://example.com/$/*")); + + result = m_browserService->searchEntries(db, "https://127.128.129.130:8448/", "https://127.128.129.130:8448/"); + QCOMPARE(result.length(), 2); + + result = m_browserService->searchEntries(db, "https://127.128.129.130/", "https://127.128.129.130/"); + QCOMPARE(result.length(), 1); + QCOMPARE(firstUrl(result[0]), QString("https://127.128.*/")); + + result = m_browserService->searchEntries(db, "https://127.1.129.130/", "https://127.1.129.130/"); + QCOMPARE(result.length(), 0); + + result = m_browserService->searchEntries(db, "https://127.160.8.2/login", "https://127.160.8.2/login"); + QCOMPARE(result.length(), 1); + QCOMPARE(firstUrl(result[0]), QString("https://127.160.*.2/login")); + + // Exact URL + result = + m_browserService->searchEntries(db, "https://thisisatest.com/login.php", "https://thisisatest.com/login.php"); + QCOMPARE(result.length(), 1); + QCOMPARE(firstUrl(result[0]), QString("\"https://thisisatest.com/login.php\"")); + + // With scheme matching enabled + browserSettings()->setMatchUrlScheme(true); + result = m_browserService->searchEntries( + db, "https://github.com/login_page/second", "https://github.com/login_page/second"); + + QCOMPARE(result.length(), 4); + QCOMPARE(firstUrl(result[0]), QString("https://github.com/login_page/*")); + QCOMPARE(firstUrl(result[1]), QString("https://github.com/*/second")); + QCOMPARE(firstUrl(result[2]), QString("https://github.com/*")); + QCOMPARE(firstUrl(result[3]), QString("github.com/*")); // Defaults to https +} + void TestBrowser::testInvalidEntries() { auto db = QSharedPointer::create(); @@ -520,14 +630,18 @@ void TestBrowser::testSubdomainsAndPaths() QCOMPARE(result.length(), 1); } -QList TestBrowser::createEntries(QStringList& urls, Group* root) const +QList TestBrowser::createEntries(QStringList& urls, Group* root, bool additionalUrl) const { QList entries; for (int i = 0; i < urls.length(); ++i) { auto entry = new Entry(); entry->setGroup(root); entry->beginUpdate(); - entry->setUrl(urls[i]); + if (additionalUrl) { + entry->attributes()->set(EntryAttributes::AdditionalUrlAttribute, urls[i]); + } else { + entry->setUrl(urls[i]); + } entry->setUsername(QString("User %1").arg(i)); entry->setUuid(QUuid::createUuid()); entry->setTitle(QString("Name_%1").arg(entry->uuidToHex())); @@ -675,3 +789,68 @@ void TestBrowser::testBestMatchingWithAdditionalURLs() QCOMPARE(sorted.length(), 1); QCOMPARE(sorted[0]->url(), urls[0]); } + +void TestBrowser::testRestrictBrowserKey() +{ + auto db = QSharedPointer::create(); + auto* root = db->rootGroup(); + + // Group 0 (root): No browser key restriction given + QStringList urlsRoot = {"https://example.com/0"}; + auto entriesRoot = createEntries(urlsRoot, root); + + // Group 1: restricted to browser with 'key1' + auto* group1 = new Group(); + group1->setParent(root); + group1->setName("TestGroup1"); + group1->customData()->set(BrowserService::OPTION_RESTRICT_KEY, "key1"); + QStringList urls1 = {"https://example.com/1"}; + auto entries1 = createEntries(urls1, group1); + + // Group 2: restricted to browser with 'key2' + auto* group2 = new Group(); + group2->setParent(root); + group2->setName("TestGroup2"); + group2->customData()->set(BrowserService::OPTION_RESTRICT_KEY, "key2"); + QStringList urls2 = {"https://example.com/2"}; + auto entries2 = createEntries(urls2, group2); + + // Group 2b: inherits parent group (2) restriction + auto* group2b = new Group(); + group2b->setParent(group2); + group2b->setName("TestGroup2b"); + QStringList urls2b = {"https://example.com/2b"}; + auto entries2b = createEntries(urls2b, group2b); + + // Group 3: inherits parent group (root) - any browser can see + auto* group3 = new Group(); + group3->setParent(root); + group3->setName("TestGroup3"); + QStringList urls3 = {"https://example.com/3"}; + auto entries3 = createEntries(urls3, group3); + + // Browser 'key0': Groups 1 and 2 are excluded, so entries 0 and 3 will be found + auto siteUrl = QString("https://example.com"); + auto result = m_browserService->searchEntries(db, siteUrl, siteUrl, {"key0"}); + auto sorted = m_browserService->sortEntries(result, siteUrl, siteUrl); + QCOMPARE(sorted.size(), 2); + QCOMPARE(sorted[0]->url(), QString("https://example.com/3")); + QCOMPARE(sorted[1]->url(), QString("https://example.com/0")); + + // Browser 'key1': Group 2 will be excluded, so entries 0, 1, and 3 will be found + result = m_browserService->searchEntries(db, siteUrl, siteUrl, {"key1"}); + sorted = m_browserService->sortEntries(result, siteUrl, siteUrl); + QCOMPARE(sorted.size(), 3); + QCOMPARE(sorted[0]->url(), QString("https://example.com/3")); + QCOMPARE(sorted[1]->url(), QString("https://example.com/1")); + QCOMPARE(sorted[2]->url(), QString("https://example.com/0")); + + // Browser 'key2': Group 1 will be excluded, so entries 0, 2, 2b, 3 will be found + result = m_browserService->searchEntries(db, siteUrl, siteUrl, {"key2"}); + sorted = m_browserService->sortEntries(result, siteUrl, siteUrl); + QCOMPARE(sorted.size(), 4); + QCOMPARE(sorted[0]->url(), QString("https://example.com/3")); + QCOMPARE(sorted[1]->url(), QString("https://example.com/2b")); + QCOMPARE(sorted[2]->url(), QString("https://example.com/2")); + QCOMPARE(sorted[3]->url(), QString("https://example.com/0")); +} diff --git a/tests/TestBrowser.h b/tests/TestBrowser.h index 48ac3b1cd..6a99e085d 100644 --- a/tests/TestBrowser.h +++ b/tests/TestBrowser.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2023 KeePassXC Team + * Copyright (C) 2025 KeePassXC Team * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -45,13 +45,15 @@ private slots: void testSearchEntriesByReference(); void testSearchEntriesWithPort(); void testSearchEntriesWithAdditionalURLs(); + void testSearchEntriesWithWildcardURLs(); void testInvalidEntries(); void testSubdomainsAndPaths(); void testBestMatchingCredentials(); void testBestMatchingWithAdditionalURLs(); + void testRestrictBrowserKey(); private: - QList createEntries(QStringList& urls, Group* root) const; + QList createEntries(QStringList& urls, Group* root, bool additionalUrl = false) const; void compareEntriesByPath(QSharedPointer db, QList entries, QString path); QScopedPointer m_browserAction; diff --git a/tests/TestCli.cpp b/tests/TestCli.cpp index 5e9c789fb..e70b7b2df 100644 --- a/tests/TestCli.cpp +++ b/tests/TestCli.cpp @@ -26,7 +26,6 @@ #include "crypto/Crypto.h" #include "keys/FileKey.h" #include "keys/drivers/YubiKey.h" -#include "zxcvbn/zxcvbn.h" #include "cli/Add.h" #include "cli/AddGroup.h" @@ -59,6 +58,7 @@ #include #include #include +#include QTEST_MAIN(TestCli) @@ -66,7 +66,9 @@ void TestCli::initTestCase() { QVERIFY(Crypto::init()); - Config::createTempFileInstance(); + // Create temporary config file + Config::createConfigFromFile(TemporaryFile::createTempConfigFile(), {}); + QLocale::setDefault(QLocale::c()); Bootstrap::bootstrap(); @@ -650,6 +652,7 @@ void TestCli::testClip() || errorOutput.contains("No program defined for clipboard manipulation")) { QSKIP("Clip test skipped due to missing clipboard tool"); } + QVERIFY(!errorOutput.contains("All clipping programs failed")); m_stderr->readLine(); // Skip password prompt QCOMPARE(m_stderr->readAll(), QByteArray()); @@ -693,7 +696,7 @@ void TestCli::testClip() // clang-format on QTRY_COMPARE(clipboard->text(), QString("Password")); - QTRY_COMPARE_WITH_TIMEOUT(clipboard->text(), QString(""), 2000); + QTRY_COMPARE_WITH_TIMEOUT(clipboard->text(), QString(""), 3000); future.waitForFinished(); @@ -704,7 +707,7 @@ void TestCli::testClip() QStringList{"clip", m_dbFile->fileName(), "/Sample Entry", "1", "-t"}); QTRY_VERIFY(isTotp(clipboard->text())); - QTRY_COMPARE_WITH_TIMEOUT(clipboard->text(), QString(""), 2000); + QTRY_COMPARE_WITH_TIMEOUT(clipboard->text(), QString(""), 3000); future.waitForFinished(); @@ -1086,8 +1089,9 @@ void TestCli::testDiceware() } smallWordFile.close(); + // Ensure a warning is shown if the wordlist is too short execCmd(dicewareCmd, {"diceware", "-W", "11", "-w", smallWordFile.fileName()}); - QCOMPARE(m_stderr->readLine(), QByteArray("The word list is too small (< 1000 items)\n")); + QVERIFY(m_stderr->readLine().length() > 0); } void TestCli::testEdit() @@ -1310,6 +1314,18 @@ void TestCli::testExport() QVERIFY(csvData.contains(QByteArray( "\"NewDatabase\",\"Sample Entry\",\"User Name\",\"Password\",\"http://www.somesite.com/\",\"Notes\""))); + // HTML exporting + setInput("a"); + execCmd(exportCmd, {"export", "-f", "html", m_dbFile->fileName()}); + QByteArray htmlHeader = m_stdout->readLine(); + QVERIFY(htmlHeader.contains(QByteArray(""))); + QByteArray htmlBody = m_stdout->readAll(); + QVERIFY(htmlBody.contains(QByteArray("

    NewDatabase

    "))); + QVERIFY(htmlBody.contains(QByteArray("Sample Entry" + "User nameUser Name" + "PasswordPassword" + "URLhttp://www.somesite.com/"))); // test invalid format setInput("a"); execCmd(exportCmd, {"export", "-f", "yaml", m_dbFile->fileName()}); diff --git a/tests/TestCsvParser.cpp b/tests/TestCsvParser.cpp index 758c31ecc..69401bfa9 100644 --- a/tests/TestCsvParser.cpp +++ b/tests/TestCsvParser.cpp @@ -22,6 +22,18 @@ QTEST_GUILESS_MAIN(TestCsvParser) +void TestCsvParser::writeToFile(const QString& contents) +{ + if (!file->open()) { + QFAIL("Cannot open temporary file!"); + } + QTextStream out(file.data()); + out.setCodec("UTF-8"); + out << contents; + out.flush(); + file->close(); +} + void TestCsvParser::initTestCase() { parser.reset(new CsvParser()); @@ -30,9 +42,7 @@ void TestCsvParser::initTestCase() void TestCsvParser::init() { file.reset(new QTemporaryFile()); - if (not file->open()) { - QFAIL("Cannot open file!"); - } + parser->setBackslashSyntax(false); parser->setComment('#'); parser->setFieldSeparator(','); @@ -47,37 +57,34 @@ void TestCsvParser::cleanup() /****************** TEST CASES ******************/ void TestCsvParser::testMissingQuote() { + writeToFile("A,B\n:BM,1"); parser->setTextQualifier(':'); - QTextStream out(file.data()); - out << "A,B\n:BM,1"; - QEXPECT_FAIL("", "Bad format", Continue); - QVERIFY(parser->parse(file.data())); - t = parser->getCsvTable(); + + QVERIFY(!parser->parse(file.data())); QWARN(parser->getStatus().toLatin1()); } void TestCsvParser::testMalformed() { + writeToFile("A,B,C\n:BM::,1,:2:"); parser->setTextQualifier(':'); - QTextStream out(file.data()); - out << "A,B,C\n:BM::,1,:2:"; - QEXPECT_FAIL("", "Bad format", Continue); - QVERIFY(parser->parse(file.data())); - t = parser->getCsvTable(); + + QVERIFY(!parser->parse(file.data())); QWARN(parser->getStatus().toLatin1()); } void TestCsvParser::testBackslashSyntax() { + // attended result: one"\t\"wo + writeToFile("Xone\\\"\\\\t\\\\\\\"w\noX\n" + "X13X,X2\\X,X,\"\"3\"X\r" + "3,X\"4\"X,,\n" + "XX\n" + "\\"); + parser->setBackslashSyntax(true); parser->setTextQualifier(QChar('X')); - QTextStream out(file.data()); - // attended result: one"\t\"wo - out << "Xone\\\"\\\\t\\\\\\\"w\noX\n" - << "X13X,X2\\X,X,\"\"3\"X\r" - << "3,X\"4\"X,,\n" - << "XX\n" - << "\\"; + QVERIFY(parser->parse(file.data())); t = parser->getCsvTable(); QVERIFY(t.at(0).at(0) == "one\"\\t\\\"w\no"); @@ -94,9 +101,9 @@ void TestCsvParser::testBackslashSyntax() void TestCsvParser::testQuoted() { - QTextStream out(file.data()); - out << "ro,w,\"end, of \"\"\"\"\"\"row\"\"\"\"\"\n" - << "2\n"; + writeToFile("ro,w,\"end, of \"\"\"\"\"\"row\"\"\"\"\"\n" + "2\n"); + QVERIFY(parser->parse(file.data())); t = parser->getCsvTable(); QVERIFY(t.at(0).at(0) == "ro"); @@ -108,8 +115,6 @@ void TestCsvParser::testQuoted() void TestCsvParser::testEmptySimple() { - QTextStream out(file.data()); - out << ""; QVERIFY(parser->parse(file.data())); t = parser->getCsvTable(); QVERIFY(t.isEmpty()); @@ -117,8 +122,8 @@ void TestCsvParser::testEmptySimple() void TestCsvParser::testEmptyQuoted() { - QTextStream out(file.data()); - out << "\"\""; + writeToFile("\"\""); + QVERIFY(parser->parse(file.data())); t = parser->getCsvTable(); QVERIFY(t.isEmpty()); @@ -126,8 +131,8 @@ void TestCsvParser::testEmptyQuoted() void TestCsvParser::testEmptyNewline() { - QTextStream out(file.data()); - out << "\"\n\""; + writeToFile("\"\n\""); + QVERIFY(parser->parse(file.data())); t = parser->getCsvTable(); QVERIFY(t.isEmpty()); @@ -142,8 +147,8 @@ void TestCsvParser::testEmptyFile() void TestCsvParser::testNewline() { - QTextStream out(file.data()); - out << "1,2\n\n\n"; + writeToFile("1,2\n\n\n"); + QVERIFY(parser->parse(file.data())); t = parser->getCsvTable(); QVERIFY(t.size() == 1); @@ -153,8 +158,8 @@ void TestCsvParser::testNewline() void TestCsvParser::testCR() { - QTextStream out(file.data()); - out << "1,2\r3,4"; + writeToFile("1,2\r3,4"); + QVERIFY(parser->parse(file.data())); t = parser->getCsvTable(); QVERIFY(t.size() == 2); @@ -166,8 +171,8 @@ void TestCsvParser::testCR() void TestCsvParser::testLF() { - QTextStream out(file.data()); - out << "1,2\n3,4"; + writeToFile("1,2\n3,4"); + QVERIFY(parser->parse(file.data())); t = parser->getCsvTable(); QVERIFY(t.size() == 2); @@ -179,8 +184,8 @@ void TestCsvParser::testLF() void TestCsvParser::testCRLF() { - QTextStream out(file.data()); - out << "1,2\r\n3,4"; + writeToFile("1,2\r\n3,4"); + QVERIFY(parser->parse(file.data())); t = parser->getCsvTable(); QVERIFY(t.size() == 2); @@ -192,12 +197,12 @@ void TestCsvParser::testCRLF() void TestCsvParser::testComments() { - QTextStream out(file.data()); - out << " #one\n" - << " \t # two, three \r\n" - << " #, sing\t with\r" - << " #\t me!\n" - << "useful,text #1!"; + writeToFile(" #one\n" + " \t # two, three \r\n" + " #, sing\t with\r" + " #\t me!\n" + "useful,text #1!"); + QVERIFY(parser->parse(file.data())); t = parser->getCsvTable(); QVERIFY(t.size() == 1); @@ -207,10 +212,10 @@ void TestCsvParser::testComments() void TestCsvParser::testColumns() { - QTextStream out(file.data()); - out << "1,2\n" - << ",,,,,,,,,a\n" - << "a,b,c,d\n"; + writeToFile("1,2\n" + ",,,,,,,,,a\n" + "a,b,c,d\n"); + QVERIFY(parser->parse(file.data())); t = parser->getCsvTable(); QVERIFY(parser->getCsvCols() == 10); @@ -218,10 +223,10 @@ void TestCsvParser::testColumns() void TestCsvParser::testSimple() { - QTextStream out(file.data()); - out << ",,2\r,2,3\n" - << "A,,B\"\n" - << " ,,\n"; + writeToFile(",,2\r,2,3\n" + "A,,B\"\n" + " ,,\n"); + QVERIFY(parser->parse(file.data())); t = parser->getCsvTable(); QVERIFY(t.size() == 4); @@ -241,11 +246,12 @@ void TestCsvParser::testSimple() void TestCsvParser::testSeparator() { + writeToFile("\t\t2\r\t2\t3\n" + "A\t\tB\"\n" + " \t\t\n"); + parser->setFieldSeparator('\t'); - QTextStream out(file.data()); - out << "\t\t2\r\t2\t3\n" - << "A\t\tB\"\n" - << " \t\t\n"; + QVERIFY(parser->parse(file.data())); t = parser->getCsvTable(); QVERIFY(t.size() == 4); @@ -265,10 +271,11 @@ void TestCsvParser::testSeparator() void TestCsvParser::testMultiline() { + writeToFile(":1\r\n2a::b:,:3\r4:\n" + "2\n"); + parser->setTextQualifier(QChar(':')); - QTextStream out(file.data()); - out << ":1\r\n2a::b:,:3\r4:\n" - << "2\n"; + QVERIFY(parser->parse(file.data())); t = parser->getCsvTable(); QVERIFY(t.at(0).at(0) == "1\n2a:b"); @@ -277,42 +284,34 @@ void TestCsvParser::testMultiline() QVERIFY(t.size() == 2); } -void TestCsvParser::testEmptyReparsing() -{ - parser->parse(nullptr); - QVERIFY(parser->reparse()); - t = parser->getCsvTable(); - QVERIFY(t.isEmpty()); -} - void TestCsvParser::testReparsing() { - QTextStream out(file.data()); - out << ":te\r\nxt1:,:te\rxt2:,:end of \"this\n string\":\n" - << "2\n"; + writeToFile(":te\r\nxt1:,:te\rxt2:,:end of \"this\n string\":\n" + "2\n"); + QVERIFY(parser->parse(file.data())); t = parser->getCsvTable(); - QEXPECT_FAIL("", "Wrong qualifier", Continue); - QVERIFY(t.at(0).at(0) == "te\nxt1"); + QCOMPARE(t.at(0).at(0), QString(":te")); parser->setTextQualifier(QChar(':')); QVERIFY(parser->reparse()); t = parser->getCsvTable(); - QVERIFY(t.at(0).at(0) == "te\nxt1"); - QVERIFY(t.at(0).at(1) == "te\nxt2"); - QVERIFY(t.at(0).at(2) == "end of \"this\n string\""); - QVERIFY(t.at(1).at(0) == "2"); - QVERIFY(t.size() == 2); + QCOMPARE(t.at(0).at(0), QString("te\nxt1")); + QCOMPARE(t.at(0).at(1), QString("te\nxt2")); + QCOMPARE(t.at(0).at(2), QString("end of \"this\n string\"")); + QCOMPARE(t.at(1).at(0), QString("2")); + QCOMPARE(t.size(), 2); } void TestCsvParser::testQualifier() { + writeToFile("X1X,X2XX,X,\"\"3\"\"\"X\r" + "3,X\"4\"X,,\n"); + parser->setTextQualifier(QChar('X')); - QTextStream out(file.data()); - out << "X1X,X2XX,X,\"\"3\"\"\"X\r" - << "3,X\"4\"X,,\n"; + QVERIFY(parser->parse(file.data())); t = parser->getCsvTable(); QVERIFY(t.size() == 2); @@ -331,10 +330,9 @@ void TestCsvParser::testUnicode() // CORRECT QString g("\u20AC"); // CORRECT QChar g(0x20AC); // ERROR QChar g("\u20AC"); + writeToFile("€1A2śA\"3śAż\"Ażac"); + parser->setFieldSeparator(QChar('A')); - QTextStream out(file.data()); - out.setCodec("UTF-8"); - out << QString("€1A2śA\"3śAż\"Ażac"); QVERIFY(parser->parse(file.data())); t = parser->getCsvTable(); diff --git a/tests/TestCsvParser.h b/tests/TestCsvParser.h index dc4429dec..0b1717a87 100644 --- a/tests/TestCsvParser.h +++ b/tests/TestCsvParser.h @@ -19,7 +19,6 @@ #ifndef KEEPASSX_TESTCSVPARSER_H #define KEEPASSX_TESTCSVPARSER_H -#include #include #include "format/CsvParser.h" @@ -38,7 +37,6 @@ private slots: void testUnicode(); void testLF(); - void testEmptyReparsing(); void testSimple(); void testEmptyQuoted(); void testEmptyNewline(); @@ -59,10 +57,11 @@ private slots: void testColumns(); private: + void writeToFile(const QString& contents); + QScopedPointer file; QScopedPointer parser; CsvTable t; - void dumpRow(CsvTable table, int row); }; #endif // KEEPASSX_TESTCSVPARSER_H diff --git a/tests/TestDatabase.cpp b/tests/TestDatabase.cpp index e3e957e79..78b6dac1d 100644 --- a/tests/TestDatabase.cpp +++ b/tests/TestDatabase.cpp @@ -124,10 +124,10 @@ void TestDatabase::testSaveAs() QCOMPARE(spyFilePathChanged.count(), 1); QVERIFY(QFile::exists(newDbFileName)); #ifdef Q_OS_WIN - QVERIFY(!QFileInfo::QFileInfo(newDbFileName).isHidden()); + QVERIFY(!QFileInfo(newDbFileName).isHidden()); SetFileAttributes(newDbFileName.toStdString().c_str(), FILE_ATTRIBUTE_HIDDEN); QVERIFY2(db->saveAs(newDbFileName, Database::Atomic, QString(), &error), error.toLatin1()); - QVERIFY(QFileInfo::QFileInfo(newDbFileName).isHidden()); + QVERIFY(QFileInfo(newDbFileName).isHidden()); #endif QFile::remove(newDbFileName); QVERIFY(!QFile::exists(newDbFileName)); @@ -164,7 +164,7 @@ void TestDatabase::testSignals() // Short delay to allow file system settling to reduce test failures Tools::wait(100); - QSignalSpy spyFileChanged(db.data(), SIGNAL(databaseFileChanged())); + QSignalSpy spyFileChanged(db.data(), &Database::databaseFileChanged); QVERIFY(tempFile.copyFromFile(dbFileName)); QTRY_COMPARE(spyFileChanged.count(), 1); QTRY_VERIFY(!db->isModified()); @@ -268,3 +268,41 @@ void TestDatabase::testCustomIcons() QCOMPARE(iconData.name, QString("Test")); QCOMPARE(iconData.lastModified, date); } + +void TestDatabase::testExternallyModified() +{ + TemporaryFile tempFile; + QVERIFY(tempFile.copyFromFile(dbFileName)); + + auto db = QSharedPointer::create(); + auto key = QSharedPointer::create(); + key->addKey(QSharedPointer::create("a")); + + QString error; + QVERIFY(db->open(tempFile.fileName(), key, &error) == true); + db->metadata()->setName("test2"); + QVERIFY(db->save(Database::Atomic, {}, &error)); + + QSignalSpy spyFileChanged(db.data(), &Database::databaseFileChanged); + QVERIFY(tempFile.copyFromFile(dbFileName)); + QTRY_COMPARE(spyFileChanged.count(), 1); + // the first argument of the databaseFileChanged signal (triggeredBySave) should be false + QVERIFY(spyFileChanged.at(0).length() == 1); + QVERIFY(spyFileChanged.at(0).at(0).type() == QVariant::Bool); + QVERIFY(spyFileChanged.at(0).at(0).toBool() == false); + spyFileChanged.clear(); + // shouldn't be able to save due to external changes + QVERIFY(db->save(Database::Atomic, {}, &error) == false); + QApplication::processEvents(); + // save should have triggered another databaseFileChanged signal + QVERIFY(spyFileChanged.count() >= 1); + // the first argument of the databaseFileChanged signal (triggeredBySave) should be true + QVERIFY(spyFileChanged.at(0).at(0).type() == QVariant::Bool); + QVERIFY(spyFileChanged.at(0).at(0).toBool() == true); + + // should be able to overwrite externally modified changes when explicitly requested + db->setIgnoreFileChangesUntilSaved(true); + QVERIFY(db->save(Database::Atomic, {}, &error)); + // ignoreFileChangesUntilSaved should reset after save + QVERIFY(db->ignoreFileChangesUntilSaved() == false); +} diff --git a/tests/TestDatabase.h b/tests/TestDatabase.h index 9f4bfab56..e23b23cf8 100644 --- a/tests/TestDatabase.h +++ b/tests/TestDatabase.h @@ -36,6 +36,7 @@ private slots: void testEmptyRecycleBinOnEmpty(); void testEmptyRecycleBinWithHierarchicalData(); void testCustomIcons(); + void testExternallyModified(); }; #endif // KEEPASSX_TESTDATABASE_H diff --git a/tests/TestDeletedObjects.cpp b/tests/TestDeletedObjects.cpp index 986ad6925..ab7d26078 100644 --- a/tests/TestDeletedObjects.cpp +++ b/tests/TestDeletedObjects.cpp @@ -37,7 +37,7 @@ void TestDeletedObjects::createAndDelete(QSharedPointer db, int delObj Group* root = db->rootGroup(); int rootChildrenCount = root->children().size(); - Group* g = new Group(); + auto g = new Group(); g->setParent(root); QUuid gUuid = QUuid::createUuid(); g->setUuid(gUuid); @@ -46,19 +46,19 @@ void TestDeletedObjects::createAndDelete(QSharedPointer db, int delObj QCOMPARE(db->deletedObjects().at(delObjectsSize - 1).uuid, gUuid); QCOMPARE(rootChildrenCount, root->children().size()); - Group* g1 = new Group(); + auto g1 = new Group(); g1->setParent(root); QUuid g1Uuid = QUuid::createUuid(); g1->setUuid(g1Uuid); - Entry* e1 = new Entry(); + auto e1 = new Entry(); e1->setGroup(g1); QUuid e1Uuid = QUuid::createUuid(); e1->setUuid(e1Uuid); - Group* g2 = new Group(); + auto g2 = new Group(); g2->setParent(g1); QUuid g2Uuid = QUuid::createUuid(); g2->setUuid(g2Uuid); - Entry* e2 = new Entry(); + auto e2 = new Entry(); e2->setGroup(g2); QUuid e2Uuid = QUuid::createUuid(); e2->setUuid(e2Uuid); @@ -73,7 +73,7 @@ void TestDeletedObjects::createAndDelete(QSharedPointer db, int delObj QCOMPARE(db->deletedObjects().at(delObjectsSize - 1).uuid, g1Uuid); QCOMPARE(rootChildrenCount, root->children().size()); - Entry* e3 = new Entry(); + auto e3 = new Entry(); e3->setGroup(root); QUuid e3Uuid = QUuid::createUuid(); e3->setUuid(e3Uuid); diff --git a/tests/TestEntry.cpp b/tests/TestEntry.cpp index 3983db101..51cb4799c 100644 --- a/tests/TestEntry.cpp +++ b/tests/TestEntry.cpp @@ -86,6 +86,7 @@ void TestEntry::testClone() { QScopedPointer entryOrg(new Entry()); entryOrg->setUuid(QUuid::createUuid()); + entryOrg->setPassword("pass"); entryOrg->setTitle("Original Title"); entryOrg->beginUpdate(); entryOrg->setTitle("New Title"); @@ -115,7 +116,7 @@ void TestEntry::testClone() QScopedPointer entryCloneRename(entryOrg->clone(Entry::CloneRenameTitle)); QCOMPARE(entryCloneRename->uuid(), entryOrg->uuid()); QCOMPARE(entryCloneRename->title(), QString("New Title - Clone")); - // Cloning should not modify time info unless explicity requested + // Cloning should not modify time info unless explicitly requested QCOMPARE(entryCloneRename->timeInfo(), entryOrg->timeInfo()); QScopedPointer entryCloneResetTime(entryOrg->clone(Entry::CloneResetTimeInfo)); @@ -320,10 +321,12 @@ void TestEntry::testResolveRecursivePlaceholders() entry7->setTitle(QString("{REF:T@I:%1} and something else").arg(entry3->uuidToHex())); entry7->setUsername(QString("{TITLE}")); entry7->setPassword(QString("PASSWORD")); + entry7->setNotes(QString("{lots} {of} {braces}")); QCOMPARE(entry7->resolvePlaceholder(entry7->title()), QString("Entry2Title and something else")); QCOMPARE(entry7->resolvePlaceholder(entry7->username()), QString("Entry2Title and something else")); QCOMPARE(entry7->resolvePlaceholder(entry7->password()), QString("PASSWORD")); + QCOMPARE(entry7->resolvePlaceholder(entry7->notes()), QString("{lots} {of} {braces}")); } void TestEntry::testResolveReferencePlaceholders() @@ -511,6 +514,86 @@ void TestEntry::testResolveNonIdPlaceholdersToUuid() } } +void TestEntry::testResolveConversionPlaceholders() +{ + Database db; + auto* root = db.rootGroup(); + + auto* entry1 = new Entry(); + entry1->setGroup(root); + entry1->setUuid(QUuid::createUuid()); + entry1->setTitle("Title1 {T-CONV:/{USERNAME}/lower/} {T-CONV:/{PASSWORD}/upper/}"); + entry1->setUsername("Username1"); + entry1->setPassword("Password1"); + entry1->setUrl("https://example.com/?test=3423&h=sdsds"); + + auto* entry2 = new Entry(); + entry2->setGroup(root); + entry2->setUuid(QUuid::createUuid()); + entry2->setTitle("Title2"); + entry2->setUsername(QString("{T-CONV:/{REF:U@I:%1}/UPPER/}").arg(entry1->uuidToHex())); + entry2->setPassword(QString("{REF:P@I:%1}").arg(entry1->uuidToHex())); + entry2->setUrl("cmd://ssh {USERNAME}@server.com -p {PASSWORD}"); + + // Test complicated and nested conversions + QCOMPARE(entry1->resolveMultiplePlaceholders(entry1->title()), QString("Title1 username1 PASSWORD1")); + QCOMPARE(entry2->resolveMultiplePlaceholders(entry2->url()), + QString("cmd://ssh USERNAME1@server.com -p Password1")); + // Test base64 and hex conversions + QCOMPARE(entry1->resolveMultiplePlaceholders("{T-CONV:/{PASSWORD}/base64/}"), QString("UGFzc3dvcmQx")); + QCOMPARE(entry1->resolveMultiplePlaceholders("{T-CONV:/{PASSWORD}/hex/}"), QString("50617373776f726431")); + // Test URL encode and decode + auto encodedURL = entry1->resolveMultiplePlaceholders("{T-CONV:/{URL}/uri/}"); + QCOMPARE(encodedURL, QString("https%3A%2F%2Fexample.com%2F%3Ftest%3D3423%26h%3Dsdsds")); + QCOMPARE(entry1->resolveMultiplePlaceholders( + "{T-CONV:/https%3A%2F%2Fexample.com%2F%3Ftest%3D3423%26h%3Dsdsds/uri-dec/}"), + entry1->url()); + // Test invalid syntax + QString error; + entry1->resolveConversionPlaceholder("{T-CONV:/{USERNAME}/junk/}", &error); + QVERIFY(!error.isEmpty()); + entry1->resolveConversionPlaceholder("{T-CONV:}", &error); + QVERIFY(!error.isEmpty()); + // Check that error gets cleared + entry1->resolveConversionPlaceholder("{T-CONV:/a/upper/}", &error); + QVERIFY(error.isEmpty()); +} + +void TestEntry::testResolveReplacePlaceholders() +{ + Database db; + auto* root = db.rootGroup(); + + auto* entry1 = new Entry(); + entry1->setGroup(root); + entry1->setUuid(QUuid::createUuid()); + entry1->setTitle("Title1"); + entry1->setUsername("Username1"); + entry1->setPassword("Password1"); + + auto* entry2 = new Entry(); + entry2->setGroup(root); + entry2->setUuid(QUuid::createUuid()); + entry2->setTitle("SAP server1 12345"); + entry2->setUsername(QString("{T-REPLACE-RX:/{REF:U@I:%1}/\\d$/2/}").arg(entry1->uuidToHex())); + entry2->setPassword(QString("{REF:P@I:%1}").arg(entry1->uuidToHex())); + entry2->setUrl( + R"(cmd://sap.exe -system={T-REPLACE-RX:/{Title}/(?i)^(.* )?(\w+(?=(\s* \d+$)))\3/$2/} -client={T-REPLACE-RX:/{Title}/(?i)^.* (?=\d+$)//} -user={USERNAME} -pw={PASSWORD})"); + + // Test complicated and nested replacements + QCOMPARE(entry2->resolveMultiplePlaceholders(entry2->url()), + QString("cmd://sap.exe -system=server1 -client=12345 -user=Username2 -pw=Password1")); + // Test invalid syntax + QString error; + entry1->resolveRegexPlaceholder("{T-REPLACE-RX:/{USERNAME}/.*+?/test/}", &error); // invalid regex + QVERIFY(!error.isEmpty()); + entry1->resolveRegexPlaceholder("{T-REPLACE-RX:/{USERNAME}/.*/}", &error); // no replacement + QVERIFY(!error.isEmpty()); + // Check that error gets cleared + entry1->resolveRegexPlaceholder("{T-REPLACE-RX:/{USERNAME}/\\d/2/}", &error); + QVERIFY(error.isEmpty()); +} + void TestEntry::testResolveClonedEntry() { Database db; @@ -591,7 +674,7 @@ void TestEntry::testResolveClonedEntry() void TestEntry::testIsRecycled() { - Entry* entry = new Entry(); + auto entry = new Entry(); QVERIFY(!entry->isRecycled()); Database db; @@ -604,10 +687,10 @@ void TestEntry::testIsRecycled() db.recycleEntry(entry); QVERIFY(entry->isRecycled()); - Group* group1 = new Group(); + auto group1 = new Group(); group1->setParent(root); - Entry* entry1 = new Entry(); + auto entry1 = new Entry(); entry1->setGroup(group1); QVERIFY(!entry1->isRecycled()); db.recycleGroup(group1); @@ -620,16 +703,16 @@ void TestEntry::testMoveUpDown() Group* root = db.rootGroup(); QVERIFY(root); - Entry* entry0 = new Entry(); + auto entry0 = new Entry(); QVERIFY(entry0); entry0->setGroup(root); - Entry* entry1 = new Entry(); + auto entry1 = new Entry(); QVERIFY(entry1); entry1->setGroup(root); - Entry* entry2 = new Entry(); + auto entry2 = new Entry(); QVERIFY(entry2); entry2->setGroup(root); - Entry* entry3 = new Entry(); + auto entry3 = new Entry(); QVERIFY(entry3); entry3->setGroup(root); // default order, straight diff --git a/tests/TestEntry.h b/tests/TestEntry.h index 3bfd8f52d..69f5b0d46 100644 --- a/tests/TestEntry.h +++ b/tests/TestEntry.h @@ -36,6 +36,8 @@ private slots: void testResolveRecursivePlaceholders(); void testResolveReferencePlaceholders(); void testResolveNonIdPlaceholdersToUuid(); + void testResolveConversionPlaceholders(); + void testResolveReplacePlaceholders(); void testResolveClonedEntry(); void testIsRecycled(); void testMoveUpDown(); diff --git a/tests/TestEntryModel.cpp b/tests/TestEntryModel.cpp index ce4b66881..e3cdb4a46 100644 --- a/tests/TestEntryModel.cpp +++ b/tests/TestEntryModel.cpp @@ -42,23 +42,23 @@ void TestEntryModel::initTestCase() void TestEntryModel::test() { - Group* group1 = new Group(); - Group* group2 = new Group(); + auto group1 = new Group(); + auto group2 = new Group(); - Entry* entry1 = new Entry(); + auto entry1 = new Entry(); entry1->setGroup(group1); entry1->setTitle("testTitle1"); - Entry* entry2 = new Entry(); + auto entry2 = new Entry(); entry2->setGroup(group1); entry2->setTitle("testTitle2"); - EntryModel* model = new EntryModel(this); + auto model = new EntryModel(this); QSignalSpy spyAboutToBeMoved(model, SIGNAL(rowsAboutToBeMoved(QModelIndex, int, int, QModelIndex, int))); QSignalSpy spyMoved(model, SIGNAL(rowsMoved(QModelIndex, int, int, QModelIndex, int))); - ModelTest* modelTest = new ModelTest(model, this); + auto modelTest = new ModelTest(model, this); model->setGroup(group1); @@ -79,7 +79,7 @@ void TestEntryModel::test() QSignalSpy spyAboutToRemove(model, SIGNAL(rowsAboutToBeRemoved(QModelIndex, int, int))); QSignalSpy spyRemoved(model, SIGNAL(rowsRemoved(QModelIndex, int, int))); - Entry* entry3 = new Entry(); + auto entry3 = new Entry(); entry3->setGroup(group1); QCOMPARE(spyAboutToBeMoved.count(), 0); @@ -130,10 +130,10 @@ void TestEntryModel::test() void TestEntryModel::testAttachmentsModel() { - EntryAttachments* entryAttachments = new EntryAttachments(this); + auto entryAttachments = new EntryAttachments(this); - EntryAttachmentsModel* model = new EntryAttachmentsModel(this); - ModelTest* modelTest = new ModelTest(model, this); + auto model = new EntryAttachmentsModel(this); + auto modelTest = new ModelTest(model, this); QCOMPARE(model->rowCount(), 0); model->setEntryAttachments(entryAttachments); @@ -164,7 +164,7 @@ void TestEntryModel::testAttachmentsModel() QSignalSpy spyReset(model, SIGNAL(modelReset())); entryAttachments->clear(); - model->setEntryAttachments(0); + model->setEntryAttachments(nullptr); QCOMPARE(spyReset.count(), 2); QCOMPARE(model->rowCount(), 0); @@ -175,10 +175,10 @@ void TestEntryModel::testAttachmentsModel() void TestEntryModel::testAttributesModel() { - EntryAttributes* entryAttributes = new EntryAttributes(this); + auto entryAttributes = new EntryAttributes(this); - EntryAttributesModel* model = new EntryAttributesModel(this); - ModelTest* modelTest = new ModelTest(model, this); + auto model = new EntryAttributesModel(this); + auto modelTest = new ModelTest(model, this); QCOMPARE(model->rowCount(), 0); model->setEntryAttributes(entryAttributes); @@ -201,6 +201,9 @@ void TestEntryModel::testAttributesModel() // make sure these don't generate messages entryAttributes->set("Title", "test"); + entryAttributes->set("UserName", "test"); + entryAttributes->set("Password", "test"); + entryAttributes->set("URL", "test"); entryAttributes->set("Notes", "test"); QCOMPARE(spyDataChanged.count(), 1); @@ -214,10 +217,20 @@ void TestEntryModel::testAttributesModel() entryAttributes->set("2nd", value, true); QVERIFY(entryAttributes->isProtected("2nd")); QCOMPARE(entryAttributes->value("2nd"), value); + entryAttributes->clear(); + + // test attribute sorting + entryAttributes->set("Test1", "1"); + entryAttributes->set("Test11", "11"); + entryAttributes->set("Test2", "2"); + QCOMPARE(model->rowCount(), 3); + QCOMPARE(model->data(model->index(0, 0)).toString(), QString("Test1")); + QCOMPARE(model->data(model->index(1, 0)).toString(), QString("Test2")); + QCOMPARE(model->data(model->index(2, 0)).toString(), QString("Test11")); QSignalSpy spyReset(model, SIGNAL(modelReset())); entryAttributes->clear(); - model->setEntryAttributes(0); + model->setEntryAttributes(nullptr); QCOMPARE(spyReset.count(), 2); QCOMPARE(model->rowCount(), 0); @@ -227,8 +240,8 @@ void TestEntryModel::testAttributesModel() void TestEntryModel::testDefaultIconModel() { - DefaultIconModel* model = new DefaultIconModel(this); - ModelTest* modelTest = new ModelTest(model, this); + auto model = new DefaultIconModel(this); + auto modelTest = new ModelTest(model, this); QCOMPARE(model->rowCount(), databaseIcons()->count()); @@ -238,8 +251,8 @@ void TestEntryModel::testDefaultIconModel() void TestEntryModel::testCustomIconModel() { - CustomIconModel* model = new CustomIconModel(this); - ModelTest* modelTest = new ModelTest(model, this); + auto model = new CustomIconModel(this); + auto modelTest = new ModelTest(model, this); QCOMPARE(model->rowCount(), 0); @@ -264,12 +277,12 @@ void TestEntryModel::testCustomIconModel() void TestEntryModel::testAutoTypeAssociationsModel() { - AutoTypeAssociationsModel* model = new AutoTypeAssociationsModel(this); - ModelTest* modelTest = new ModelTest(model, this); + auto model = new AutoTypeAssociationsModel(this); + auto modelTest = new ModelTest(model, this); QCOMPARE(model->rowCount(), 0); - AutoTypeAssociations* associations = new AutoTypeAssociations(this); + auto associations = new AutoTypeAssociations(this); model->setAutoTypeAssociations(associations); QCOMPARE(model->rowCount(), 0); @@ -300,28 +313,24 @@ void TestEntryModel::testAutoTypeAssociationsModel() void TestEntryModel::testProxyModel() { - EntryModel* modelSource = new EntryModel(this); - SortFilterHideProxyModel* modelProxy = new SortFilterHideProxyModel(this); + auto modelSource = new EntryModel(this); + auto modelProxy = new SortFilterHideProxyModel(this); modelProxy->setSourceModel(modelSource); - ModelTest* modelTest = new ModelTest(modelProxy, this); + auto modelTest = new ModelTest(modelProxy, this); - Database* db = new Database(); - Entry* entry = new Entry(); + auto db = new Database(); + auto entry = new Entry(); entry->setTitle("Test Title"); entry->setGroup(db->rootGroup()); modelSource->setGroup(db->rootGroup()); - /** - * @author Fonic - * Update comparison value of modelProxy->columnCount() to account for - * additional columns 'Password', 'Notes', 'Expires', 'Created', 'Modified', - * 'Accessed', 'Paperclip', 'Attachments', and TOTP - */ + // Test hiding and showing a column + auto columnCount = modelProxy->columnCount(); QSignalSpy spyColumnRemove(modelProxy, SIGNAL(columnsAboutToBeRemoved(QModelIndex, int, int))); modelProxy->hideColumn(0, true); - QCOMPARE(modelProxy->columnCount(), 14); + QCOMPARE(modelProxy->columnCount(), columnCount - 1); QVERIFY(!spyColumnRemove.isEmpty()); int oldSpyColumnRemoveSize = spyColumnRemove.size(); @@ -335,15 +344,9 @@ void TestEntryModel::testProxyModel() entryList << entry; modelSource->setEntries(entryList); - /** - * @author Fonic - * Update comparison value of modelProxy->columnCount() to account for - * additional columns 'Password', 'Notes', 'Expires', 'Created', 'Modified', - * 'Accessed', 'Paperclip', 'Attachments', and TOTP - */ QSignalSpy spyColumnInsert(modelProxy, SIGNAL(columnsAboutToBeInserted(QModelIndex, int, int))); modelProxy->hideColumn(0, false); - QCOMPARE(modelProxy->columnCount(), 15); + QCOMPARE(modelProxy->columnCount(), columnCount); QVERIFY(!spyColumnInsert.isEmpty()); int oldSpyColumnInsertSize = spyColumnInsert.size(); @@ -358,18 +361,18 @@ void TestEntryModel::testProxyModel() void TestEntryModel::testDatabaseDelete() { - EntryModel* model = new EntryModel(this); - ModelTest* modelTest = new ModelTest(model, this); + auto model = new EntryModel(this); + auto modelTest = new ModelTest(model, this); - Database* db1 = new Database(); - Group* group1 = new Group(); + auto db1 = new Database(); + auto group1 = new Group(); group1->setParent(db1->rootGroup()); - Entry* entry1 = new Entry(); + auto entry1 = new Entry(); entry1->setGroup(group1); - Database* db2 = new Database(); - Entry* entry2 = new Entry(); + auto db2 = new Database(); + auto entry2 = new Entry(); entry2->setGroup(db2->rootGroup()); model->setEntries(QList() << entry1 << entry2); diff --git a/tests/TestEntrySearcher.cpp b/tests/TestEntrySearcher.cpp index 2292c253e..d002a3166 100644 --- a/tests/TestEntrySearcher.cpp +++ b/tests/TestEntrySearcher.cpp @@ -18,6 +18,7 @@ #include "TestEntrySearcher.h" #include "core/Group.h" #include "core/Tools.h" +#include "core/Totp.h" #include @@ -45,21 +46,21 @@ void TestEntrySearcher::testSearch() * - group211 * - group2111 */ - Group* group1 = new Group(); - Group* group2 = new Group(); - Group* group3 = new Group(); + auto group1 = new Group(); + auto group2 = new Group(); + auto group3 = new Group(); group1->setParent(m_rootGroup); group2->setParent(m_rootGroup); group3->setParent(m_rootGroup); - Group* group11 = new Group(); + auto group11 = new Group(); group11->setParent(group1); - Group* group21 = new Group(); - Group* group211 = new Group(); - Group* group2111 = new Group(); + auto group21 = new Group(); + auto group211 = new Group(); + auto group2111 = new Group(); group21->setParent(group2); group211->setParent(group21); @@ -67,39 +68,39 @@ void TestEntrySearcher::testSearch() group1->setSearchingEnabled(Group::Disable); - Entry* eRoot = new Entry(); + auto eRoot = new Entry(); eRoot->setTitle("test search term test"); eRoot->setGroup(m_rootGroup); - Entry* eRoot2 = new Entry(); + auto eRoot2 = new Entry(); eRoot2->setNotes("test term test"); eRoot2->setGroup(m_rootGroup); // Searching is disabled for these - Entry* e1 = new Entry(); + auto e1 = new Entry(); e1->setUsername("test search term test"); e1->setGroup(group1); - Entry* e11 = new Entry(); + auto e11 = new Entry(); e11->setNotes("test search term test"); e11->setGroup(group11); // End searching disabled - Entry* e2111 = new Entry(); + auto e2111 = new Entry(); e2111->setTitle("test search term test"); e2111->setGroup(group2111); - Entry* e2111b = new Entry(); + auto e2111b = new Entry(); e2111b->setNotes("test search test"); e2111b->setUsername("user123"); e2111b->setPassword("testpass"); e2111b->setGroup(group2111); - Entry* e3 = new Entry(); + auto e3 = new Entry(); e3->setUrl("test search term test"); e3->setGroup(group3); - Entry* e3b = new Entry(); + auto e3b = new Entry(); e3b->setTitle("test search test 123"); e3b->setUsername("test@email.com"); e3b->setPassword("realpass"); @@ -154,7 +155,7 @@ void TestEntrySearcher::testSearch() void TestEntrySearcher::testAndConcatenationInSearch() { - Entry* entry = new Entry(); + auto entry = new Entry(); entry->setNotes("abc def ghi"); entry->setTitle("jkl"); entry->setGroup(m_rootGroup); @@ -180,7 +181,7 @@ void TestEntrySearcher::testAndConcatenationInSearch() void TestEntrySearcher::testAllAttributesAreSearched() { - Entry* entry = new Entry(); + auto entry = new Entry(); entry->setGroup(m_rootGroup); entry->setTitle("testTitle"); @@ -277,35 +278,35 @@ void TestEntrySearcher::testGroup() * - group2 * - subgroup2 (1 entry) */ - Group* group1 = new Group(); - Group* group2 = new Group(); + auto group1 = new Group(); + auto group2 = new Group(); group1->setParent(m_rootGroup); group1->setName("group1"); group2->setParent(m_rootGroup); group2->setName("group2"); - Group* subgroup1 = new Group(); + auto subgroup1 = new Group(); subgroup1->setName("subgroup1"); subgroup1->setParent(group1); - Group* subgroup2 = new Group(); + auto subgroup2 = new Group(); subgroup2->setName("subgroup2"); subgroup2->setParent(group2); - Entry* eGroup1 = new Entry(); + auto eGroup1 = new Entry(); eGroup1->setTitle("Entry Group 1"); eGroup1->setGroup(group1); - Entry* eSub1 = new Entry(); + auto eSub1 = new Entry(); eSub1->setTitle("test search term test"); eSub1->setGroup(subgroup1); - Entry* eSub2 = new Entry(); + auto eSub2 = new Entry(); eSub2->setNotes("test test"); eSub2->setGroup(subgroup1); - Entry* eSub3 = new Entry(); + auto eSub3 = new Entry(); eSub3->setNotes("test term test"); eSub3->setGroup(subgroup2); @@ -364,7 +365,7 @@ void TestEntrySearcher::testSkipProtected() m_entrySearcher.search("_testProtected:apple _testAttribute:testE1 _testAttribute:testE2", m_rootGroup); QCOMPARE(m_searchResult, {}); - // also move the protected term around to execurise the short-circut logic + // also move the protected term around to exercise the short-circuit logic m_searchResult = m_entrySearcher.search("_testAttribute:testE2 _testProtected:apple", m_rootGroup); QCOMPARE(m_searchResult, expectE2); m_searchResult = m_entrySearcher.search("_testAttribute:testE1 _testProtected:apple", m_rootGroup); @@ -394,3 +395,42 @@ void TestEntrySearcher::testUUIDSearch() m_searchResult = m_entrySearcher.search("uuid:" + Tools::uuidToHex(uuid1), m_rootGroup); QCOMPARE(m_searchResult.count(), 1); } + +void TestEntrySearcher::testTotpSearch() +{ + auto entry1 = new Entry(); + entry1->setGroup(m_rootGroup); + entry1->setTitle("Regular Entry"); + + auto entry2 = new Entry(); + entry2->setGroup(m_rootGroup); + entry2->setTitle("TOTP Entry"); + // Set up TOTP on entry2 + auto totpSettings = Totp::createSettings("GEZDGNBVGY3TQOJQGEZDGNBVGY3TQOJQ", 6, 30); + entry2->setTotp(totpSettings); + + auto entry3 = new Entry(); + entry3->setGroup(m_rootGroup); + entry3->setTitle("Another TOTP Entry"); + // Set up TOTP on entry3 + auto totpSettings2 = Totp::createSettings("MFRGG43UEBUXGIDBKRWXAZLSMUQGG6LQ", 6, 30); + entry3->setTotp(totpSettings2); + + // Test searching for TOTP entries + m_searchResult = m_entrySearcher.search("has:totp", m_rootGroup); + QCOMPARE(m_searchResult.count(), 2); + QVERIFY(m_searchResult.contains(entry2)); + QVERIFY(m_searchResult.contains(entry3)); + QVERIFY(!m_searchResult.contains(entry1)); + + // Test case insensitive search + m_searchResult = m_entrySearcher.search("has:TOTP", m_rootGroup); + QCOMPARE(m_searchResult.count(), 2); + + // Test excluding TOTP entries + m_searchResult = m_entrySearcher.search("!has:totp", m_rootGroup); + QCOMPARE(m_searchResult.count(), 1); + QVERIFY(m_searchResult.contains(entry1)); + QVERIFY(!m_searchResult.contains(entry2)); + QVERIFY(!m_searchResult.contains(entry3)); +} diff --git a/tests/TestEntrySearcher.h b/tests/TestEntrySearcher.h index 2ca81a742..54a45d578 100644 --- a/tests/TestEntrySearcher.h +++ b/tests/TestEntrySearcher.h @@ -39,6 +39,7 @@ private slots: void testGroup(); void testSkipProtected(); void testUUIDSearch(); + void testTotpSearch(); private: Group* m_rootGroup; diff --git a/tests/TestFdoSecrets.cpp b/tests/TestFdoSecrets.cpp index 0f4c374a4..38a50af99 100644 --- a/tests/TestFdoSecrets.cpp +++ b/tests/TestFdoSecrets.cpp @@ -69,7 +69,7 @@ void TestFdoSecrets::testSpecialCharsInAttributeValue() e2->setTitle("titleB"); e2->attributes()->set("testAttribute", "Abc:*+.-"); - // search for custom entries via programatic API + // search for custom entries via programmatic API { const auto term = Collection::attributeToTerm("testAttribute", "OAuth::[test.name@gmail.com]"); const auto res = EntrySearcher().search({term}, root.data()); diff --git a/tests/TestGroup.cpp b/tests/TestGroup.cpp index 826ecba88..22807c878 100644 --- a/tests/TestGroup.cpp +++ b/tests/TestGroup.cpp @@ -56,9 +56,9 @@ void TestGroup::cleanup() void TestGroup::testParenting() { - Database* db = new Database(); + auto db = new Database(); QPointer rootGroup = db->rootGroup(); - Group* tmpRoot = new Group(); + auto tmpRoot = new Group(); QPointer g1 = new Group(); QPointer g2 = new Group(); @@ -98,8 +98,8 @@ void TestGroup::testParenting() QVERIFY(g1->children().at(1) == g3); QVERIFY(g3->children().contains(g4)); - Group* g5 = new Group(); - Group* g6 = new Group(); + auto g5 = new Group(); + auto g6 = new Group(); g5->setParent(db->rootGroup()); g6->setParent(db->rootGroup()); QVERIFY(db->rootGroup()->children().at(1) == g5); @@ -129,8 +129,8 @@ void TestGroup::testParenting() void TestGroup::testSignals() { - Database* db = new Database(); - Database* db2 = new Database(); + auto db = new Database(); + auto db2 = new Database(); QPointer root = db->rootGroup(); QSignalSpy spyAboutToAdd(db, SIGNAL(groupAboutToAdd(Group*, int))); @@ -147,8 +147,8 @@ void TestGroup::testSignals() QSignalSpy spyAboutToMove2(db2, SIGNAL(groupAboutToMove(Group*, Group*, int))); QSignalSpy spyMoved2(db2, SIGNAL(groupMoved())); - Group* g1 = new Group(); - Group* g2 = new Group(); + auto g1 = new Group(); + auto g2 = new Group(); g1->setParent(root); QCOMPARE(spyAboutToAdd.count(), 1); @@ -212,8 +212,8 @@ void TestGroup::testSignals() QCOMPARE(spyAboutToMove2.count(), 0); QCOMPARE(spyMoved2.count(), 0); - Group* g3 = new Group(); - Group* g4 = new Group(); + auto g3 = new Group(); + auto g4 = new Group(); g3->setParent(root); QCOMPARE(spyAboutToAdd.count(), 3); @@ -247,7 +247,7 @@ void TestGroup::testSignals() void TestGroup::testEntries() { - Group* group = new Group(); + auto group = new Group(); QPointer entry1 = new Entry(); entry1->setGroup(group); @@ -269,8 +269,8 @@ void TestGroup::testDeleteSignals() { QScopedPointer db(new Database()); Group* groupRoot = db->rootGroup(); - Group* groupChild = new Group(); - Group* groupChildChild = new Group(); + auto groupChild = new Group(); + auto groupChildChild = new Group(); groupRoot->setObjectName("groupRoot"); groupChild->setObjectName("groupChild"); groupChildChild->setObjectName("groupChildChild"); @@ -284,8 +284,8 @@ void TestGroup::testDeleteSignals() QCOMPARE(spyAboutToRemove.count(), 2); QCOMPARE(spyRemoved.count(), 2); - Group* group = new Group(); - Entry* entry = new Entry(); + auto group = new Group(); + auto entry = new Entry(); entry->setGroup(group); QSignalSpy spyEntryAboutToRemove(group, SIGNAL(entryAboutToRemove(Entry*))); QSignalSpy spyEntryRemoved(group, SIGNAL(entryRemoved(Entry*))); @@ -298,9 +298,9 @@ void TestGroup::testDeleteSignals() QScopedPointer db2(new Database()); Group* groupRoot2 = db2->rootGroup(); - Group* group2 = new Group(); + auto group2 = new Group(); group2->setParent(groupRoot2); - Entry* entry2 = new Entry(); + auto entry2 = new Entry(); entry2->setGroup(group2); QSignalSpy spyEntryAboutToRemove2(group2, SIGNAL(entryAboutToRemove(Entry*))); QSignalSpy spyEntryRemoved2(group2, SIGNAL(entryRemoved(Entry*))); @@ -476,15 +476,15 @@ void TestGroup::testFindEntry() { QScopedPointer db(new Database()); - Entry* entry1 = new Entry(); + auto entry1 = new Entry(); entry1->setTitle(QString("entry1")); entry1->setGroup(db->rootGroup()); entry1->setUuid(QUuid::createUuid()); - Group* group1 = new Group(); + auto group1 = new Group(); group1->setName("group1"); - Entry* entry2 = new Entry(); + auto entry2 = new Entry(); entry2->setTitle(QString("entry2")); entry2->setGroup(group1); @@ -558,11 +558,11 @@ void TestGroup::testFindGroupByPath() { QScopedPointer db(new Database()); - Group* group1 = new Group(); + auto group1 = new Group(); group1->setName("group1"); group1->setParent(db->rootGroup()); - Group* group2 = new Group(); + auto group2 = new Group(); group2->setName("group2"); group2->setParent(group1); @@ -626,7 +626,7 @@ void TestGroup::testPrint() output = db->rootGroup()->print(true); QCOMPARE(output, QString("[empty]\n")); - Entry* entry1 = new Entry(); + auto entry1 = new Entry(); entry1->setTitle(QString("entry1")); entry1->setGroup(db->rootGroup()); entry1->setUuid(QUuid::createUuid()); @@ -634,24 +634,24 @@ void TestGroup::testPrint() output = db->rootGroup()->print(); QCOMPARE(output, QString("entry1\n")); - Group* group1 = new Group(); + auto group1 = new Group(); group1->setName("group1"); group1->setParent(db->rootGroup()); - Entry* entry2 = new Entry(); + auto entry2 = new Entry(); entry2->setTitle(QString("entry2")); entry2->setGroup(group1); entry2->setUuid(QUuid::createUuid()); - Group* group2 = new Group(); + auto group2 = new Group(); group2->setName("group2"); group2->setParent(db->rootGroup()); - Group* subGroup = new Group(); + auto subGroup = new Group(); subGroup->setName("subgroup"); subGroup->setParent(group2); - Entry* entry3 = new Entry(); + auto entry3 = new Entry(); entry3->setTitle(QString("entry3")); entry3->setGroup(subGroup); entry3->setUuid(QUuid::createUuid()); @@ -691,13 +691,13 @@ void TestGroup::testPrint() void TestGroup::testAddEntryWithPath() { - Database* db = new Database(); + auto db = new Database(); - Group* group1 = new Group(); + auto group1 = new Group(); group1->setName("group1"); group1->setParent(db->rootGroup()); - Group* group2 = new Group(); + auto group2 = new Group(); group2->setName("group2"); group2->setParent(group1); @@ -742,19 +742,19 @@ void TestGroup::testIsRecycled() Database db; db.metadata()->setRecycleBinEnabled(true); - Group* group1 = new Group(); + auto group1 = new Group(); group1->setName("group1"); group1->setParent(db.rootGroup()); - Group* group2 = new Group(); + auto group2 = new Group(); group2->setName("group2"); group2->setParent(db.rootGroup()); - Group* group3 = new Group(); + auto group3 = new Group(); group3->setName("group3"); group3->setParent(group2); - Group* group4 = new Group(); + auto group4 = new Group(); group4->setName("group4"); group4->setParent(db.rootGroup()); @@ -814,64 +814,64 @@ void TestGroup::testEquals() void TestGroup::testChildrenSort() { auto createTestGroupWithUnorderedChildren = []() -> Group* { - Group* parent = new Group(); + auto parent = new Group(); - Group* group1 = new Group(); + auto group1 = new Group(); group1->setName("B"); group1->setParent(parent); - Group* group2 = new Group(); + auto group2 = new Group(); group2->setName("e"); group2->setParent(parent); - Group* group3 = new Group(); + auto group3 = new Group(); group3->setName("Test999"); group3->setParent(parent); - Group* group4 = new Group(); + auto group4 = new Group(); group4->setName("A"); group4->setParent(parent); - Group* group5 = new Group(); + auto group5 = new Group(); group5->setName("z"); group5->setParent(parent); - Group* group6 = new Group(); + auto group6 = new Group(); group6->setName("045"); group6->setParent(parent); - Group* group7 = new Group(); + auto group7 = new Group(); group7->setName("60"); group7->setParent(parent); - Group* group8 = new Group(); + auto group8 = new Group(); group8->setName("04test"); group8->setParent(parent); - Group* group9 = new Group(); + auto group9 = new Group(); group9->setName("Test12"); group9->setParent(parent); - Group* group10 = new Group(); + auto group10 = new Group(); group10->setName("i"); group10->setParent(parent); - Group* subGroup1 = new Group(); + auto subGroup1 = new Group(); subGroup1->setName("sub_xte"); subGroup1->setParent(group10); - Group* subGroup2 = new Group(); + auto subGroup2 = new Group(); subGroup2->setName("sub_010"); subGroup2->setParent(group10); - Group* subGroup3 = new Group(); + auto subGroup3 = new Group(); subGroup3->setName("sub_000"); subGroup3->setParent(group10); - Group* subGroup4 = new Group(); + auto subGroup4 = new Group(); subGroup4->setName("sub_M"); subGroup4->setParent(group10); - Group* subGroup5 = new Group(); + auto subGroup5 = new Group(); subGroup5->setName("sub_p"); subGroup5->setParent(group10); - Group* subGroup6 = new Group(); + auto subGroup6 = new Group(); subGroup6->setName("sub_45p"); subGroup6->setParent(group10); - Group* subGroup7 = new Group(); + auto subGroup7 = new Group(); subGroup7->setName("sub_6p"); subGroup7->setParent(group10); - Group* subGroup8 = new Group(); + auto subGroup8 = new Group(); subGroup8->setName("sub_tt"); subGroup8->setParent(group10); - Group* subGroup9 = new Group(); + auto subGroup9 = new Group(); subGroup9->setName("sub_t0"); subGroup9->setParent(group10); @@ -996,11 +996,11 @@ void TestGroup::testHierarchy() Group group1; group1.setName("group1"); - Group* group2 = new Group(); + auto group2 = new Group(); group2->setName("group2"); group2->setParent(&group1); - Group* group3 = new Group(); + auto group3 = new Group(); group3->setName("group3"); group3->setParent(group2); @@ -1028,12 +1028,12 @@ void TestGroup::testApplyGroupIconRecursively() // Create a database with two nested groups with one entry each Database database; - Group* subgroup = new Group(); + auto subgroup = new Group(); subgroup->setName("Subgroup"); subgroup->setParent(database.rootGroup()); QVERIFY(subgroup); - Group* subsubgroup = new Group(); + auto subsubgroup = new Group(); subsubgroup->setName("Subsubgroup"); subsubgroup->setParent(subgroup); QVERIFY(subsubgroup); @@ -1125,7 +1125,7 @@ void TestGroup::testUsernamesRecursive() Database database; // Create a subgroup - Group* subgroup = new Group(); + auto subgroup = new Group(); subgroup->setName("Subgroup"); subgroup->setParent(database.rootGroup()); @@ -1152,16 +1152,16 @@ void TestGroup::testMoveUpDown() Group* root = database.rootGroup(); QVERIFY(root); - Entry* entry0 = new Entry(); + auto entry0 = new Entry(); QVERIFY(entry0); entry0->setGroup(root); - Entry* entry1 = new Entry(); + auto entry1 = new Entry(); QVERIFY(entry1); entry1->setGroup(root); - Entry* entry2 = new Entry(); + auto entry2 = new Entry(); QVERIFY(entry2); entry2->setGroup(root); - Entry* entry3 = new Entry(); + auto entry3 = new Entry(); QVERIFY(entry3); entry3->setGroup(root); // default order, straight diff --git a/tests/TestGroupModel.cpp b/tests/TestGroupModel.cpp index 6d7e58c41..f9a0790fc 100644 --- a/tests/TestGroupModel.cpp +++ b/tests/TestGroupModel.cpp @@ -35,35 +35,35 @@ void TestGroupModel::initTestCase() void TestGroupModel::test() { - Database* db = new Database(); + auto db = new Database(); Group* groupRoot = db->rootGroup(); groupRoot->setObjectName("groupRoot"); groupRoot->setName("groupRoot"); - Group* group1 = new Group(); + auto group1 = new Group(); group1->setObjectName("group1"); group1->setName("group1"); group1->setParent(groupRoot); - Group* group11 = new Group(); + auto group11 = new Group(); group1->setObjectName("group11"); group11->setName("group11"); group11->setParent(group1); - Group* group12 = new Group(); + auto group12 = new Group(); group1->setObjectName("group12"); group12->setName("group12"); group12->setParent(group1); - Group* group121 = new Group(); + auto group121 = new Group(); group1->setObjectName("group121"); group121->setName("group121"); group121->setParent(group12); - GroupModel* model = new GroupModel(db, this); + auto model = new GroupModel(db, this); - ModelTest* modelTest = new ModelTest(model, this); + auto modelTest = new ModelTest(model, this); QModelIndex indexRoot = model->index(0, 0); QModelIndex index1 = model->index(0, 0, indexRoot); @@ -90,7 +90,7 @@ void TestGroupModel::test() QSignalSpy spyAboutToMove(model, SIGNAL(rowsAboutToBeMoved(QModelIndex, int, int, QModelIndex, int))); QSignalSpy spyMoved(model, SIGNAL(rowsMoved(QModelIndex, int, int, QModelIndex, int))); - Group* group2 = new Group(); + auto group2 = new Group(); group2->setObjectName("group2"); group2->setName("group2"); group2->setParent(groupRoot); diff --git a/tests/TestHibp.cpp b/tests/TestHibp.cpp index 65e858cbe..5e85f0728 100644 --- a/tests/TestHibp.cpp +++ b/tests/TestHibp.cpp @@ -89,22 +89,22 @@ void TestHibp::testPwned() Group* root = m_db->rootGroup(); - Entry* entry1 = new Entry(); + auto entry1 = new Entry(); entry1->setPassword("foo"); entry1->setGroup(root); - Entry* entry2 = new Entry(); + auto entry2 = new Entry(); entry2->setPassword("xyz"); entry2->setGroup(root); - Entry* entry3 = new Entry(); + auto entry3 = new Entry(); entry3->setPassword("foo"); m_db->recycleEntry(entry3); - Group* group1 = new Group(); + auto group1 = new Group(); group1->setParent(root); - Entry* entry4 = new Entry(); + auto entry4 = new Entry(); entry4->setPassword("bar"); entry4->setGroup(group1); diff --git a/tests/TestIconDownloader.cpp b/tests/TestIconDownloader.cpp index 77b21e3e7..676734ee6 100644 --- a/tests/TestIconDownloader.cpp +++ b/tests/TestIconDownloader.cpp @@ -1,6 +1,9 @@ #include "TestIconDownloader.h" + #include -#include + +#include "core/Config.h" +#include "gui/IconDownloader.h" QTEST_GUILESS_MAIN(TestIconDownloader) @@ -8,6 +11,7 @@ void TestIconDownloader::testIconDownloader() { QFETCH(QString, url); QFETCH(QStringList, expectation); + config()->set(Config::Security_IconDownloadFallback, false); IconDownloader downloader; downloader.setUrl(url); diff --git a/tests/TestImports.cpp b/tests/TestImports.cpp index 84ef26cce..17ec2bef5 100644 --- a/tests/TestImports.cpp +++ b/tests/TestImports.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2022 KeePassXC Team + * Copyright (C) 2024 KeePassXC Team * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -25,6 +25,7 @@ #include "format/BitwardenReader.h" #include "format/OPUXReader.h" #include "format/OpVaultReader.h" +#include "format/ProtonPassReader.h" #include #include @@ -96,6 +97,11 @@ void TestImports::testOPUX() QVERIFY(entry); // Check custom group icon QVERIFY(!entry->group()->iconUuid().isNull()); + + // Check Category UUID 05 Passwords + entry = db->rootGroup()->findEntryByPath("/Personal/UUID 005 Password"); + QVERIFY(entry); + QCOMPARE(entry->password(), QStringLiteral("uuid005password")); } void TestImports::testOPVault() @@ -277,3 +283,91 @@ void TestImports::testBitwardenEncrypted() } QVERIFY(db); } + +void TestImports::testBitwardenPasskey() +{ + auto bitwardenPath = + QStringLiteral("%1/%2").arg(KEEPASSX_TEST_DATA_DIR, QStringLiteral("/bitwarden_passkey_export.json")); + + BitwardenReader reader; + auto db = reader.convert(bitwardenPath); + QVERIFY2(!reader.hasError(), qPrintable(reader.errorString())); + QVERIFY(db); + + // Confirm Login fields + auto entry = db->rootGroup()->findEntryByPath("/webauthn.io"); + QVERIFY(entry); + QCOMPARE(entry->title(), QStringLiteral("webauthn.io")); + QCOMPARE(entry->username(), QStringLiteral("KPXC_BITWARDEN")); + QCOMPARE(entry->url(), QStringLiteral("https://webauthn.io/")); + + // Confirm passkey attributes + auto attr = entry->attributes(); + QCOMPARE(attr->value(EntryAttributes::KPEX_PASSKEY_CREDENTIAL_ID), QStringLiteral("o-FfiyfBQq6Qz6YVrYeFTw")); + QCOMPARE( + attr->value(EntryAttributes::KPEX_PASSKEY_PRIVATE_KEY_PEM), + QStringLiteral( + "-----BEGIN PRIVATE " + "KEY-----" + "MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgmr4GQQjerojFuf0ZouOuUllMvAwxZSZAfB6gwDYcLiehRANCAAT0WR5zVS" + "p6ieusvjkLkzaGc7fjGBmwpiuLPxR/d+ZjqMI9L2DKh+takp6wGt2x0n4jzr1KA352NZg0vjZX9CHh-----END PRIVATE KEY-----")); + QCOMPARE(attr->value(EntryAttributes::KPEX_PASSKEY_USERNAME), QStringLiteral("KPXC_BITWARDEN")); + QCOMPARE(attr->value(EntryAttributes::KPEX_PASSKEY_RELYING_PARTY), QStringLiteral("webauthn.io")); + QCOMPARE(attr->value(EntryAttributes::KPEX_PASSKEY_USER_HANDLE), + QStringLiteral("aTFtdmFnOHYtS2dxVEJ0by1rSFpLWGg0enlTVC1iUVJReDZ5czJXa3c2aw")); +} + +void TestImports::testProtonPass() +{ + auto protonPassPath = + QStringLiteral("%1/%2").arg(KEEPASSX_TEST_DATA_DIR, QStringLiteral("/protonpass_export.json")); + + ProtonPassReader reader; + auto db = reader.convert(protonPassPath); + QVERIFY2(!reader.hasError(), qPrintable(reader.errorString())); + QVERIFY(db); + + // Confirm Login fields + auto entry = db->rootGroup()->findEntryByPath("/Personal/Test Login"); + QVERIFY(entry); + QCOMPARE(entry->title(), QStringLiteral("Test Login")); + QCOMPARE(entry->username(), QStringLiteral("Username")); + QCOMPARE(entry->password(), QStringLiteral("Password")); + QCOMPARE(entry->url(), QStringLiteral("https://example.com/")); + QCOMPARE(entry->notes(), QStringLiteral("My login secure note.")); + // Check extra URL's + QCOMPARE(entry->attribute("KP2A_URL_1"), QStringLiteral("https://example2.com/")); + // Check TOTP + QVERIFY(entry->hasTotp()); + // Check attributes + auto attr = entry->attributes(); + QVERIFY(attr->isProtected("hidden field")); + QCOMPARE(attr->value("second 2fa secret"), QStringLiteral("TOTPCODE")); + // NOTE: Proton Pass does not export attachments + // NOTE: Proton Pass does not export expiration dates + + // Confirm Secure Note + entry = db->rootGroup()->findEntryByPath("/Personal/My Secure Note"); + QVERIFY(entry); + QCOMPARE(entry->notes(), QStringLiteral("Secure note contents.")); + + // Confirm Credit Card + entry = db->rootGroup()->findEntryByPath("/Personal/Test Card"); + QVERIFY(entry); + QCOMPARE(entry->username(), QStringLiteral("1234222233334444")); + QCOMPARE(entry->password(), QStringLiteral("333")); + attr = entry->attributes(); + QCOMPARE(attr->value("card_cardholderName"), QStringLiteral("Test name")); + QCOMPARE(attr->value("card_expirationDate"), QStringLiteral("2025-01")); + QCOMPARE(attr->value("card_pin"), QStringLiteral("1234")); + QVERIFY(attr->isProtected("card_pin")); + + // Confirm Expired (deleted) entry + entry = db->rootGroup()->findEntryByPath("/Personal/My Deleted Note"); + QVERIFY(entry); + QTRY_VERIFY(entry->isExpired()); + + // Confirm second group (vault) + entry = db->rootGroup()->findEntryByPath("/Test/Other vault login"); + QVERIFY(entry); +} diff --git a/tests/TestImports.h b/tests/TestImports.h index 2e00de9a6..728fa6377 100644 --- a/tests/TestImports.h +++ b/tests/TestImports.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2022 KeePassXC Team + * Copyright (C) 2024 KeePassXC Team * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -30,6 +30,8 @@ private slots: void testOPVault(); void testBitwarden(); void testBitwardenEncrypted(); + void testBitwardenPasskey(); + void testProtonPass(); }; #endif /* TEST_IMPORTS_H */ diff --git a/tests/TestKdbx4.cpp b/tests/TestKdbx4.cpp index ec1d6875f..3233d570a 100644 --- a/tests/TestKdbx4.cpp +++ b/tests/TestKdbx4.cpp @@ -24,13 +24,10 @@ #include "format/KeePass2.h" #include "format/KeePass2Reader.h" #include "format/KeePass2Writer.h" -#ifdef WITH_XC_KEESHARE -#include "keeshare/KeeShare.h" -#include "keeshare/KeeShareSettings.h" -#endif #include "keys/FileKey.h" #include "keys/PasswordKey.h" #include "mock/MockChallengeResponseKey.h" +#include "mock/MockClock.h" #include int main(int argc, char* argv[]) @@ -117,6 +114,17 @@ void TestKdbx4AesKdf::initTestCaseImpl() } Q_DECLARE_METATYPE(QUuid) + +void TestKdbx4Format::init() +{ + MockClock::setup(new MockClock()); +} + +void TestKdbx4Format::cleanup() +{ + MockClock::teardown(); +} + void TestKdbx4Format::testFormat400() { QString filename = QString(KEEPASSX_TEST_DATA_DIR).append("/Format400.kdbx"); @@ -429,13 +437,8 @@ void TestKdbx4Format::testAttachmentIndexStability() group2->setUuid(QUuid::createUuid()); QVERIFY(!group2->uuid().isNull()); group2->setParent(group1); -#ifdef WITH_XC_KEESHARE - KeeShareSettings::Reference ref; - ref.type = KeeShareSettings::SynchronizeWith; - ref.path = "123"; - KeeShare::setReferenceTo(group2, ref); - QVERIFY(KeeShare::isShared(group2)); -#endif + group2->customData()->set("KeeShare/Reference", "value doesn't matter"); + QVERIFY(group2->isShared()); auto attachment1 = QByteArray("qwerty"); auto attachment2 = QByteArray("asdf"); @@ -498,9 +501,9 @@ void TestKdbx4Format::testAttachmentIndexStability() QCOMPARE(a2->value("a"), attachment1); QCOMPARE(a2->value("b"), attachment2); -#ifdef WITH_XC_KEESHARE - QVERIFY(KeeShare::isShared(db2->rootGroup()->findEntryByUuid(uuid3)->group())); -#endif + auto sharedGroup = db2->rootGroup()->findEntryByUuid(uuid3)->group(); + QVERIFY(sharedGroup->isShared()); + auto a3 = db2->rootGroup()->findEntryByUuid(uuid3)->attachments(); QCOMPARE(a3->keys().size(), 4); QCOMPARE(a3->values().size(), 3); diff --git a/tests/TestKdbx4.h b/tests/TestKdbx4.h index aa2011e74..cd5bc4788 100644 --- a/tests/TestKdbx4.h +++ b/tests/TestKdbx4.h @@ -56,6 +56,8 @@ class TestKdbx4Format : public QObject Q_OBJECT private slots: + void init(); + void cleanup(); void testFormat400(); void testFormat400Upgrade(); void testFormat400Upgrade_data(); diff --git a/tests/TestKeePass1Reader.cpp b/tests/TestKeePass1Reader.cpp index a3676a460..18b35b5c7 100644 --- a/tests/TestKeePass1Reader.cpp +++ b/tests/TestKeePass1Reader.cpp @@ -39,7 +39,7 @@ void TestKeePass1Reader::initTestCase() QString filename = QString(KEEPASSX_TEST_DATA_DIR).append("/basic.kdb"); KeePass1Reader reader; - m_db = reader.readDatabase(filename, "masterpw", 0); + m_db = reader.readDatabase(filename, "masterpw", nullptr); QVERIFY(m_db); QVERIFY(!reader.hasError()); } @@ -213,7 +213,7 @@ void TestKeePass1Reader::testTwofish() QString dbFilename = QString("%1/%2.kdb").arg(QString(KEEPASSX_TEST_DATA_DIR), name); - auto db = reader.readDatabase(dbFilename, "masterpw", 0); + auto db = reader.readDatabase(dbFilename, "masterpw", nullptr); QVERIFY(db); QVERIFY(!reader.hasError()); QCOMPARE(db->rootGroup()->children().size(), 1); @@ -229,7 +229,7 @@ void TestKeePass1Reader::testCP1252Password() QString dbFilename = QString("%1/%2.kdb").arg(QString(KEEPASSX_TEST_DATA_DIR), name); QString password = QString::fromUtf8("\xe2\x80\x9e\x70\x61\x73\x73\x77\x6f\x72\x64\xe2\x80\x9d"); - auto db = reader.readDatabase(dbFilename, password, 0); + auto db = reader.readDatabase(dbFilename, password, nullptr); QVERIFY(db); QVERIFY(!reader.hasError()); QCOMPARE(db->rootGroup()->children().size(), 1); @@ -244,7 +244,7 @@ QDateTime TestKeePass1Reader::genDT(int year, int month, int day, int hour, int { QDate date(year, month, day); QTime time(hour, min, 0); - return QDateTime(date, time, Qt::UTC); + return {date, time, Qt::UTC}; } void TestKeePass1Reader::reopenDatabase(QSharedPointer db, diff --git a/tests/TestMerge.cpp b/tests/TestMerge.cpp index 8386191dd..3dde3a063 100644 --- a/tests/TestMerge.cpp +++ b/tests/TestMerge.cpp @@ -29,13 +29,6 @@ QTEST_GUILESS_MAIN(TestMerge) namespace { - TimeInfo modificationTime(TimeInfo timeInfo, int years, int months, int days) - { - const QDateTime time = timeInfo.lastModificationTime(); - timeInfo.setLastModificationTime(time.addYears(years).addMonths(months).addDays(days)); - return timeInfo; - } - MockClock* m_clock = nullptr; } // namespace @@ -79,7 +72,7 @@ void TestMerge::testMergeIntoNew() } /** - * Merging when no changes occured should not + * Merging when no changes occurred should not * have any side effect. */ void TestMerge::testMergeNoChanges() @@ -294,50 +287,6 @@ void TestMerge::testResolveConflictExisting() } } -/** - * Tests the KeepBoth merge mode. - */ -void TestMerge::testResolveConflictDuplicate() -{ - QScopedPointer dbDestination(createTestDatabase()); - QScopedPointer dbSource( - createTestDatabaseStructureClone(dbDestination.data(), Entry::CloneIncludeHistory, Group::CloneIncludeEntries)); - - // sanity check - QCOMPARE(dbDestination->rootGroup()->children().at(0)->entries().size(), 2); - - // make this entry newer than in original db - QPointer updatedDestinationEntry = dbDestination->rootGroup()->children().at(0)->entries().at(0); - const TimeInfo initialEntryTimeInfo = updatedDestinationEntry->timeInfo(); - const TimeInfo updatedEntryTimeInfo = modificationTime(initialEntryTimeInfo, 1, 0, 0); - - updatedDestinationEntry->setTimeInfo(updatedEntryTimeInfo); - - dbDestination->rootGroup()->setMergeMode(Group::MergeMode::Duplicate); - - // Make sure the merge changes have a different timestamp. - m_clock->advanceSecond(1); - - Merger merger(dbSource.data(), dbDestination.data()); - merger.merge(); - - // one entry is duplicated because of mode - QCOMPARE(dbDestination->rootGroup()->children().at(0)->entries().size(), 3); - QCOMPARE(dbDestination->rootGroup()->children().at(0)->entries().at(0)->historyItems().isEmpty(), false); - // the older entry was merged from the other db as last in the group - QPointer newerEntry = dbDestination->rootGroup()->children().at(0)->entries().at(0); - QPointer olderEntry = dbDestination->rootGroup()->children().at(0)->entries().at(2); - QVERIFY(newerEntry->title() == olderEntry->title()); - QVERIFY2(!newerEntry->attributes()->hasKey("merged"), "newer entry is not marked with an attribute \"merged\""); - QVERIFY2(olderEntry->attributes()->hasKey("merged"), "older entry is marked with an attribute \"merged\""); - QCOMPARE(olderEntry->historyItems().isEmpty(), false); - QCOMPARE(newerEntry->timeInfo(), updatedEntryTimeInfo); - // TODO HNH: this may be subject to discussions since the entry itself is newer but represents an older one - // QCOMPARE(olderEntry->timeInfo(), initialEntryTimeInfo); - QVERIFY2(olderEntry->uuidToHex() != updatedDestinationEntry->uuidToHex(), - "KeepBoth should not reuse the UUIDs when cloning."); -} - void TestMerge::testResolveConflictTemplate( int mergeMode, std::function&)> verification) @@ -346,7 +295,7 @@ void TestMerge::testResolveConflictTemplate( timestamps["initialTime"] = m_clock->currentDateTimeUtc(); QScopedPointer dbDestination(createTestDatabase()); - Entry* deletedEntry1 = new Entry(); + auto deletedEntry1 = new Entry(); deletedEntry1->setUuid(QUuid::createUuid()); deletedEntry1->beginUpdate(); @@ -354,7 +303,7 @@ void TestMerge::testResolveConflictTemplate( deletedEntry1->setTitle("deletedDestination"); deletedEntry1->endUpdate(); - Entry* deletedEntry2 = new Entry(); + auto deletedEntry2 = new Entry(); deletedEntry2->setUuid(QUuid::createUuid()); deletedEntry2->beginUpdate(); @@ -429,7 +378,7 @@ void TestMerge::testResolveConflictTemplate( m_clock->advanceMinute(1); - Entry* destinationEntrySingle = new Entry(); + auto destinationEntrySingle = new Entry(); destinationEntrySingle->setUuid(QUuid::createUuid()); destinationEntrySingle->beginUpdate(); @@ -437,7 +386,7 @@ void TestMerge::testResolveConflictTemplate( destinationEntrySingle->setTitle("entryDestination"); destinationEntrySingle->endUpdate(); - Entry* sourceEntrySingle = new Entry(); + auto sourceEntrySingle = new Entry(); sourceEntrySingle->setUuid(QUuid::createUuid()); sourceEntrySingle->beginUpdate(); @@ -491,7 +440,7 @@ void TestMerge::testDeletionConflictTemplate(int mergeMode, // entry indirectly deleted in target after updated in source auto createGroup = [&](const char* name, Group* parent) { - Group* group = new Group(); + auto group = new Group(); group->setUuid(QUuid::createUuid()); group->setName(name); group->setParent(parent, 0); @@ -499,7 +448,7 @@ void TestMerge::testDeletionConflictTemplate(int mergeMode, return group; }; auto createEntry = [&](const char* title, Group* parent) { - Entry* entry = new Entry(); + auto entry = new Entry(); entry->setUuid(QUuid::createUuid()); entry->setTitle(title); entry->setGroup(parent); @@ -620,7 +569,7 @@ void TestMerge::assertDeletionNewerOnly(Database* db, const QMap // newer deletion in source forces deletion QVERIFY(!mergedRootGroup->findEntryByUuid(identifiers["EntryDeletedInSourceAfterChangedInTarget"])); QVERIFY(db->containsDeletedObject(identifiers["EntryDeletedInSourceAfterChangedInTarget"])); - // newer change in source privents deletion + // newer change in source prevents deletion QVERIFY(mergedRootGroup->findEntryByUuid(identifiers["EntryDeletedInTargetBeforeChangedInSource"])); QVERIFY(!db->containsDeletedObject(identifiers["EntryDeletedInTargetBeforeChangedInSource"])); // newer deletion in target forces deletion @@ -636,7 +585,7 @@ void TestMerge::assertDeletionNewerOnly(Database* db, const QMap QVERIFY(db->containsDeletedObject(identifiers["GroupDeletedInSourceAfterEntryUpdatedInTarget"])); QVERIFY(!mergedRootGroup->findEntryByUuid(identifiers["EntryDeletedInSourceAfterEntryUpdatedInTarget"])); QVERIFY(db->containsDeletedObject(identifiers["EntryDeletedInSourceAfterEntryUpdatedInTarget"])); - // newer change in source privents deletion + // newer change in source prevents deletion QVERIFY(mergedRootGroup->findGroupByUuid(identifiers["GroupDeletedInTargetBeforeEntryUpdatedInSource"])); QVERIFY(!db->containsDeletedObject(identifiers["GroupDeletedInTargetBeforeEntryUpdatedInSource"])); QVERIFY(mergedRootGroup->findEntryByUuid(identifiers["EntryDeletedInTargetBeforeEntryUpdatedInSource"])); @@ -769,26 +718,11 @@ void TestMerge::testDeletionConflictEntry_Synchronized() testDeletionConflictTemplate(Group::Synchronize, &TestMerge::assertDeletionNewerOnly); } -void TestMerge::testDeletionConflictEntry_KeepLocal() -{ - testDeletionConflictTemplate(Group::KeepLocal, &TestMerge::assertDeletionLocalOnly); -} - -void TestMerge::testDeletionConflictEntry_KeepRemote() -{ - testDeletionConflictTemplate(Group::KeepRemote, &TestMerge::assertDeletionLocalOnly); -} - void TestMerge::testDeletionConflictEntry_KeepNewer() { testDeletionConflictTemplate(Group::KeepNewer, &TestMerge::assertDeletionLocalOnly); } -void TestMerge::testDeletionConflictEntry_Duplicate() -{ - testDeletionConflictTemplate(Group::Duplicate, &TestMerge::assertDeletionLocalOnly); -} - /** * Tests the KeepNewer mode concerning history. */ @@ -802,29 +736,6 @@ void TestMerge::testResolveConflictEntry_Synchronize() }); } -/** - * Tests the KeepExisting mode concerning history. - */ -void TestMerge::testResolveConflictEntry_KeepLocal() -{ - testResolveConflictTemplate(Group::KeepLocal, [](Database* db, const QMap& timestamps) { - QPointer mergedRootGroup = db->rootGroup(); - QPointer mergedGroup1 = mergedRootGroup->children().at(0); - TestMerge::assertUpdateMergedEntry1(mergedGroup1->entries().at(0), timestamps); - TestMerge::assertUpdateReappliedEntry2(mergedGroup1->entries().at(1), timestamps); - }); -} - -void TestMerge::testResolveConflictEntry_KeepRemote() -{ - testResolveConflictTemplate(Group::KeepRemote, [](Database* db, const QMap& timestamps) { - QPointer mergedRootGroup = db->rootGroup(); - QPointer mergedGroup1 = mergedRootGroup->children().at(0); - TestMerge::assertUpdateReappliedEntry1(mergedGroup1->entries().at(0), timestamps); - TestMerge::assertUpdateMergedEntry2(mergedGroup1->entries().at(1), timestamps); - }); -} - void TestMerge::testResolveConflictEntry_KeepNewer() { testResolveConflictTemplate(Group::KeepNewer, [](Database* db, const QMap& timestamps) { @@ -919,7 +830,7 @@ void TestMerge::testCreateNewGroups() m_clock->advanceSecond(1); - Group* groupSourceCreated = new Group(); + auto groupSourceCreated = new Group(); groupSourceCreated->setName("group3"); groupSourceCreated->setUuid(QUuid::createUuid()); groupSourceCreated->setParent(dbSource->rootGroup()); @@ -942,7 +853,7 @@ void TestMerge::testMoveEntryIntoNewGroup() m_clock->advanceSecond(1); - Group* groupSourceCreated = new Group(); + auto groupSourceCreated = new Group(); groupSourceCreated->setName("group3"); groupSourceCreated->setUuid(QUuid::createUuid()); groupSourceCreated->setParent(dbSource->rootGroup()); @@ -977,7 +888,7 @@ void TestMerge::testUpdateEntryDifferentLocation() QScopedPointer dbSource( createTestDatabaseStructureClone(dbDestination.data(), Entry::CloneNoFlags, Group::CloneIncludeEntries)); - Group* groupDestinationCreated = new Group(); + auto groupDestinationCreated = new Group(); groupDestinationCreated->setName("group3"); groupDestinationCreated->setUuid(QUuid::createUuid()); groupDestinationCreated->setParent(dbDestination->rootGroup()); @@ -1015,7 +926,7 @@ void TestMerge::testUpdateEntryDifferentLocation() QCOMPARE(entryDestinationMerged->username(), QString("username")); QCOMPARE(entryDestinationMerged->group()->name(), QString("group3")); QCOMPARE(uuidBeforeSyncing, entryDestinationMerged->uuid()); - // default merge strategie is KeepNewer - therefore the older location is used! + // default merge strategy is KeepNewer - therefore the older location is used! QCOMPARE(entryDestinationMerged->timeInfo().locationChanged(), sourceLocationChanged); } @@ -1064,7 +975,7 @@ void TestMerge::testUpdateGroup() void TestMerge::testUpdateGroupLocation() { QScopedPointer dbDestination(createTestDatabase()); - Group* group3DestinationCreated = new Group(); + auto group3DestinationCreated = new Group(); QUuid group3Uuid = QUuid::createUuid(); group3DestinationCreated->setUuid(group3Uuid); group3DestinationCreated->setName("group3"); @@ -1320,7 +1231,7 @@ void TestMerge::testDeletedGroup() QPointer group2DestinationInitial = dbDestination->rootGroup()->findChildByName("group2"); QVERIFY(group2DestinationInitial != nullptr); - Entry* entry3DestinationCreated = new Entry(); + auto entry3DestinationCreated = new Entry(); entry3DestinationCreated->beginUpdate(); entry3DestinationCreated->setUuid(QUuid::createUuid()); entry3DestinationCreated->setGroup(group2DestinationInitial); @@ -1543,19 +1454,19 @@ void TestMerge::testMergeModified() Database* TestMerge::createTestDatabase() { - Database* db = new Database(); + auto db = new Database(); - Group* group1 = new Group(); + auto group1 = new Group(); group1->setName("group1"); group1->setUuid(QUuid::createUuid()); - Group* group2 = new Group(); + auto group2 = new Group(); group2->setName("group2"); group2->setUuid(QUuid::createUuid()); - Entry* entry1 = new Entry(); + auto entry1 = new Entry(); entry1->setUuid(QUuid::createUuid()); - Entry* entry2 = new Entry(); + auto entry2 = new Entry(); entry2->setUuid(QUuid::createUuid()); m_clock->advanceYear(1); diff --git a/tests/TestMerge.h b/tests/TestMerge.h index 6990a5dbe..b9ea54f72 100644 --- a/tests/TestMerge.h +++ b/tests/TestMerge.h @@ -36,15 +36,9 @@ private slots: void testResolveGroupConflictOlder(); void testMergeNotModified(); void testMergeModified(); - void testResolveConflictDuplicate(); void testResolveConflictEntry_Synchronize(); - void testResolveConflictEntry_KeepLocal(); - void testResolveConflictEntry_KeepRemote(); void testResolveConflictEntry_KeepNewer(); - void testDeletionConflictEntry_Duplicate(); void testDeletionConflictEntry_Synchronized(); - void testDeletionConflictEntry_KeepLocal(); - void testDeletionConflictEntry_KeepRemote(); void testDeletionConflictEntry_KeepNewer(); void testMoveEntry(); void testMoveEntryPreserveChanges(); diff --git a/tests/TestOpenSSHKey.cpp b/tests/TestOpenSSHKey.cpp index 1f0053474..a20b248ed 100644 --- a/tests/TestOpenSSHKey.cpp +++ b/tests/TestOpenSSHKey.cpp @@ -254,6 +254,7 @@ void TestOpenSSHKey::testParseRSACompare() QCOMPARE(oldKey.type(), newKey.type()); QCOMPARE(oldKey.fingerprint(), newKey.fingerprint()); QCOMPARE(oldPrivateKey, newPrivateKey); + QCOMPARE(newKeyString, newKey.privateKey()); } void TestOpenSSHKey::testParseECDSA256() @@ -277,6 +278,7 @@ void TestOpenSSHKey::testParseECDSA256() QCOMPARE(key.type(), QString("ecdsa-sha2-nistp256")); QCOMPARE(key.comment(), QString("opensshkey-test-ecdsa256@keepassxc")); QCOMPARE(key.fingerprint(), QString("SHA256:nwwovZmQbBeiR3GZRpK4OWHgCUE7E0wFtCN7Ng7eX5g")); + QCOMPARE(keyString, key.privateKey()); } void TestOpenSSHKey::testParseECDSA384() @@ -302,6 +304,7 @@ void TestOpenSSHKey::testParseECDSA384() QCOMPARE(key.type(), QString("ecdsa-sha2-nistp384")); QCOMPARE(key.comment(), QString("opensshkey-test-ecdsa384@keepassxc")); QCOMPARE(key.fingerprint(), QString("SHA256:B5tLMG976BZ6nyi/oRUmKaTJcaEaFagEjBfOAgru0OY")); + QCOMPARE(keyString, key.privateKey()); } void TestOpenSSHKey::testParseECDSA521() @@ -328,6 +331,7 @@ void TestOpenSSHKey::testParseECDSA521() QCOMPARE(key.type(), QString("ecdsa-sha2-nistp521")); QCOMPARE(key.comment(), QString("opensshkey-test-ecdsa521@keepassxc")); QCOMPARE(key.fingerprint(), QString("SHA256:m3LtA9MtZW8FN0R3vwA0AAI+YtegbggGCy3EGKWya+s")); + QCOMPARE(keyString, key.privateKey()); } void TestOpenSSHKey::testDecryptOpenSSHAES256CBC() @@ -533,6 +537,7 @@ void TestOpenSSHKey::testParseECDSASecurityKey() QCOMPARE(key.type(), QString("sk-ecdsa-sha2-nistp256@openssh.com")); QCOMPARE(key.comment(), QString("opensshkey-test-ecdsa-sk@keepassxc")); QCOMPARE(key.fingerprint(), QString("SHA256:ctOtAsPMqbtumGI41o2oeWfGDah4m1ACILRj+x0gx0E")); + QCOMPARE(keyString, key.privateKey()); } void TestOpenSSHKey::testParseED25519SecurityKey() @@ -557,4 +562,5 @@ void TestOpenSSHKey::testParseED25519SecurityKey() QCOMPARE(key.type(), QString("sk-ssh-ed25519@openssh.com")); QCOMPARE(key.comment(), QString("opensshkey-test-ed25519-sk@keepassxc")); QCOMPARE(key.fingerprint(), QString("SHA256:PGtS5WvbnYmNqFIeRbzO6cVP9GLh8eEzENgkHp02XIA")); + QCOMPARE(keyString, key.privateKey()); } diff --git a/tests/TestPasskeys.cpp b/tests/TestPasskeys.cpp index 1618dce28..fd25c2baf 100644 --- a/tests/TestPasskeys.cpp +++ b/tests/TestPasskeys.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2024 KeePassXC Team + * Copyright (C) 2025 KeePassXC Team * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -440,12 +440,12 @@ void TestPasskeys::testGet() auto response = publicKeyCredential["response"].toObject(); QCOMPARE(response["authenticatorData"].toString(), QString("dKbqkhPJnC90siSSsyDPQCYqlMGpUKA5fyklC2CEHvAFAAAAAA")); QCOMPARE(response["clientDataJSON"].toString(), - QString("eyJjaGFsbGVuZ2UiOiI5ejM2dlRmUVRMOTVMZjdXblpneXRlN29oR2VGLVhSaUx4a0wtTHVHVTF6b3BSbU1JVUExTFZ3ekdwe" - "UltMWZPQm4xUW5SYTBRSDI3QURBYUpHSHlzUSIsImNyb3NzT3JpZ2luIjpmYWxzZSwib3JpZ2luIjoiaHR0cHM6Ly93ZWJhdX" - "Robi5pbyIsInR5cGUiOiJ3ZWJhdXRobi5nZXQifQ")); + QString("eyJ0eXBlIjoid2ViYXV0aG4uZ2V0IiwiY2hhbGxlbmdlIjoiOXozNnZUZlFUTDk1TGY3V25aZ3l0ZTdvaEdlRi1YUmlMeGtML" + "Ux1R1Uxem9wUm1NSVVBMUxWd3pHcHlJbTFmT0JuMVFuUmEwUUgyN0FEQWFKR0h5c1EiLCJvcmlnaW4iOiJodHRwczovL3dlYm" + "F1dGhuLmlvIiwiY3Jvc3NPcmlnaW4iOmZhbHNlfQ")); QCOMPARE( response["signature"].toString(), - QString("MEUCIHFv0lOOGGloi_XoH5s3QDSs__8yAp9ZTMEjNiacMpOxAiEA04LAfO6TE7j12XNxd3zHQpn4kZN82jQFPntPiPBSD5c")); + QString("MEYCIQCpbDaYJ4b2ofqWBxfRNbH3XCpsyao7Iui5lVuJRU9HIQIhAPl5moNZgJu5zmurkKK_P900Ct6wd3ahVIqCEqTeeRdE")); auto clientDataJson = response["clientDataJSON"].toString(); auto clientDataByteArray = browserMessageBuilder()->getArrayFromBase64(clientDataJson); diff --git a/tests/TestPassphraseGenerator.cpp b/tests/TestPassphraseGenerator.cpp index 9b1ed8ada..7b8dd89a4 100644 --- a/tests/TestPassphraseGenerator.cpp +++ b/tests/TestPassphraseGenerator.cpp @@ -16,6 +16,7 @@ */ #include "TestPassphraseGenerator.h" +#include "config-keepassx-tests.h" #include "core/PassphraseGenerator.h" #include "crypto/Crypto.h" @@ -33,7 +34,7 @@ void TestPassphraseGenerator::testWordCase() { PassphraseGenerator generator; generator.setWordSeparator(" "); - QVERIFY(generator.isValid()); + QVERIFY(generator.isWordListValid()); QString passphrase; passphrase = generator.generatePassphrase(); @@ -49,6 +50,21 @@ void TestPassphraseGenerator::testWordCase() generator.setWordCase(PassphraseGenerator::TITLECASE); passphrase = generator.generatePassphrase(); - QRegularExpression regex("^([A-Z][a-z]* ?)+$"); - QVERIFY(regex.match(passphrase).hasMatch()); + QRegularExpression regex("^(?:[A-Z][a-z-]* )*[A-Z][a-z-]*$"); + QVERIFY2(regex.match(passphrase).hasMatch(), qPrintable(passphrase)); +} + +void TestPassphraseGenerator::testUniqueEntriesInWordlist() +{ + PassphraseGenerator generator; + // set the limit down, so we don't have to do a very large file + generator.m_minWordListSize = 4; + + // link to bad wordlist + QString path = QString(KEEPASSX_TEST_DATA_DIR).append("/wordlists/bad_wordlist_with_duplicate_entries.wordlist"); + + // setting will work, it creates the warning however, and isWordListValid will fail + generator.setWordList(path); + // so this fails + QVERIFY(!generator.isWordListValid()); } diff --git a/tests/TestPassphraseGenerator.h b/tests/TestPassphraseGenerator.h index ca0fd0664..a4d86055a 100644 --- a/tests/TestPassphraseGenerator.h +++ b/tests/TestPassphraseGenerator.h @@ -27,6 +27,7 @@ class TestPassphraseGenerator : public QObject private slots: void initTestCase(); void testWordCase(); + void testUniqueEntriesInWordlist(); }; #endif // KEEPASSXC_TESTPASSPHRASEGENERATOR_H diff --git a/tests/TestSSHAgent.cpp b/tests/TestSSHAgent.cpp index 3acf3352a..986def7b8 100644 --- a/tests/TestSSHAgent.cpp +++ b/tests/TestSSHAgent.cpp @@ -20,6 +20,7 @@ #include "core/Config.h" #include "crypto/Crypto.h" #include "sshagent/KeeAgentSettings.h" +#include "sshagent/OpenSSHKeyGen.h" #include "sshagent/SSHAgent.h" #include @@ -29,20 +30,21 @@ QTEST_GUILESS_MAIN(TestSSHAgent) void TestSSHAgent::initTestCase() { QVERIFY(Crypto::init()); - Config::createTempFileInstance(); - m_agentSocketFile.setAutoRemove(true); - QVERIFY(m_agentSocketFile.open()); + // Create temporary config file + Config::createConfigFromFile(TemporaryFile::createTempConfigFile(), {}); - m_agentSocketFileName = m_agentSocketFile.fileName(); + // default config must not enable agent + SSHAgent agent; + QVERIFY(!agent.isEnabled()); + + m_agentSocketFile.reset(new TemporaryFile(this)); + + m_agentSocketFileName = m_agentSocketFile->fileName(); QVERIFY(!m_agentSocketFileName.isEmpty()); - // let ssh-agent re-create it as a socket - QVERIFY(m_agentSocketFile.remove()); - QStringList arguments; - arguments << "-D" - << "-a" << m_agentSocketFileName; + arguments << "-D" << "-a" << m_agentSocketFileName; QElapsedTimer timer; timer.start(); @@ -56,7 +58,7 @@ void TestSSHAgent::initTestCase() QSKIP("ssh-agent could not be started"); } - qDebug() << "ssh-agent started as pid" << m_agentProcess.pid(); + qDebug() << "ssh-agent started as pid" << m_agentProcess.processId(); // we need to wait for the agent to open the socket before going into real tests QFileInfo socketFileInfo(m_agentSocketFileName); @@ -85,13 +87,18 @@ void TestSSHAgent::initTestCase() QVERIFY(m_key.parsePKCS1PEM(keyData)); } +void TestSSHAgent::init() +{ + // Reset the config state + SSHAgent agent; + agent.setEnabled(false); + QString empty; + agent.setAuthSockOverride(empty); +} + void TestSSHAgent::testConfiguration() { SSHAgent agent; - - // default config must not enable agent - QVERIFY(!agent.isEnabled()); - agent.setEnabled(true); QVERIFY(agent.isEnabled()); @@ -224,13 +231,71 @@ void TestSSHAgent::testToOpenSSHKey() QVERIFY(!key.publicKey().isEmpty()); } +void TestSSHAgent::testKeyGenRSA() +{ + SSHAgent agent; + agent.setEnabled(true); + agent.setAuthSockOverride(m_agentSocketFileName); + + QVERIFY(agent.isAgentRunning()); + + OpenSSHKey key; + KeeAgentSettings settings; + bool keyInAgent; + + QVERIFY(OpenSSHKeyGen::generateRSA(key, 2048)); + + QVERIFY(agent.addIdentity(key, settings, m_uuid)); + QVERIFY(agent.checkIdentity(key, keyInAgent) && keyInAgent); + QVERIFY(agent.removeIdentity(key)); + QVERIFY(agent.checkIdentity(key, keyInAgent) && !keyInAgent); +} + +void TestSSHAgent::testKeyGenECDSA() +{ + SSHAgent agent; + agent.setEnabled(true); + agent.setAuthSockOverride(m_agentSocketFileName); + + QVERIFY(agent.isAgentRunning()); + + OpenSSHKey key; + KeeAgentSettings settings; + bool keyInAgent; + + QVERIFY(OpenSSHKeyGen::generateECDSA(key, 256)); + + QVERIFY(agent.addIdentity(key, settings, m_uuid)); + QVERIFY(agent.checkIdentity(key, keyInAgent) && keyInAgent); + QVERIFY(agent.removeIdentity(key)); + QVERIFY(agent.checkIdentity(key, keyInAgent) && !keyInAgent); +} + +void TestSSHAgent::testKeyGenEd25519() +{ + SSHAgent agent; + agent.setEnabled(true); + agent.setAuthSockOverride(m_agentSocketFileName); + + QVERIFY(agent.isAgentRunning()); + + OpenSSHKey key; + KeeAgentSettings settings; + bool keyInAgent; + + QVERIFY(OpenSSHKeyGen::generateEd25519(key)); + + QVERIFY(agent.addIdentity(key, settings, m_uuid)); + QVERIFY(agent.checkIdentity(key, keyInAgent) && keyInAgent); + QVERIFY(agent.removeIdentity(key)); + QVERIFY(agent.checkIdentity(key, keyInAgent) && !keyInAgent); +} + void TestSSHAgent::cleanupTestCase() { if (m_agentProcess.state() != QProcess::NotRunning) { - qDebug() << "Killing ssh-agent pid" << m_agentProcess.pid(); + qDebug() << "Killing ssh-agent pid" << m_agentProcess.processId(); m_agentProcess.terminate(); m_agentProcess.waitForFinished(); } - - m_agentSocketFile.remove(); } diff --git a/tests/TestSSHAgent.h b/tests/TestSSHAgent.h index 12c115b23..db06fd806 100644 --- a/tests/TestSSHAgent.h +++ b/tests/TestSSHAgent.h @@ -19,8 +19,8 @@ #define TESTSSHAGENT_H #include "sshagent/OpenSSHKey.h" +#include "util/TemporaryFile.h" #include -#include #include class TestSSHAgent : public QObject @@ -29,16 +29,20 @@ class TestSSHAgent : public QObject private slots: void initTestCase(); + void init(); void testConfiguration(); void testIdentity(); void testRemoveOnClose(); void testLifetimeConstraint(); void testConfirmConstraint(); void testToOpenSSHKey(); + void testKeyGenRSA(); + void testKeyGenECDSA(); + void testKeyGenEd25519(); void cleanupTestCase(); private: - QTemporaryFile m_agentSocketFile; + QScopedPointer m_agentSocketFile; QString m_agentSocketFileName; QProcess m_agentProcess; OpenSSHKey m_key; diff --git a/tests/TestSharing.cpp b/tests/TestSharing.cpp index 14a72b142..0b5414ea8 100644 --- a/tests/TestSharing.cpp +++ b/tests/TestSharing.cpp @@ -117,12 +117,9 @@ void TestSharing::testReferenceSerialization_data() QTest::addColumn("path"); QTest::addColumn("uuid"); QTest::addColumn("type"); - QTest::newRow("1") << "Password" - << "/some/path" << QUuid::createUuid() << int(KeeShareSettings::Inactive); - QTest::newRow("2") << "" - << "" << QUuid() << int(KeeShareSettings::SynchronizeWith); - QTest::newRow("3") << "" - << "/some/path" << QUuid() << int(KeeShareSettings::ExportTo); + QTest::newRow("1") << "Password" << "/some/path" << QUuid::createUuid() << int(KeeShareSettings::Inactive); + QTest::newRow("2") << "" << "" << QUuid() << int(KeeShareSettings::SynchronizeWith); + QTest::newRow("3") << "" << "/some/path" << QUuid() << int(KeeShareSettings::ExportTo); } void TestSharing::testSettingsSerialization() diff --git a/tests/TestTools.cpp b/tests/TestTools.cpp index f5c192f69..a373e1523 100644 --- a/tests/TestTools.cpp +++ b/tests/TestTools.cpp @@ -18,7 +18,9 @@ #include "TestTools.h" #include "core/Clock.h" +#include "core/Tools.h" +#include #include #include #include @@ -150,18 +152,22 @@ void TestTools::testBackupFilePatternSubstitution_data() QTest::newRow("Default time pattern (empty formatter)") << "{TIME:}" << DEFAULT_DB_FILE_PATH << DEFAULT_FORMATTED_TIME; QTest::newRow("Custom time pattern") << "{TIME:dd-ss}" << DEFAULT_DB_FILE_PATH << NOW.toString("dd-ss"); + QTest::newRow("Time pattern twice") << "{TIME:yy} {TIME}" << DEFAULT_DB_FILE_PATH + << NOW.toString("yy") + QStringLiteral(" ") + DEFAULT_FORMATTED_TIME; + QTest::newRow("Complex custom time pattern") + << "./{TIME:yy}/{DB_FILENAME}_{TIME:yyyyMMdd_HHmmss}.old.kdbx" << DEFAULT_DB_FILE_PATH + << QStringLiteral("./") + NOW.toString("yy") + QStringLiteral("/") + DEFAULT_DB_FILE_NAME + QStringLiteral("_") + + NOW.toString("yyyyMMdd_HHmmss") + QStringLiteral(".old.kdbx"); QTest::newRow("Invalid custom time pattern") << "{TIME:dd/-ss}" << DEFAULT_DB_FILE_PATH << NOW.toString("dd/-ss"); QTest::newRow("Recursive substitution") << "{TIME:'{TIME}'}" << DEFAULT_DB_FILE_PATH << DEFAULT_FORMATTED_TIME; QTest::newRow("{DB_FILENAME} substitution") << "some {DB_FILENAME} thing" << DEFAULT_DB_FILE_PATH << QStringLiteral("some ") + DEFAULT_DB_FILE_NAME + QStringLiteral(" thing"); - QTest::newRow("{DB_FILENAME} substitution with multiple extensions") << "some {DB_FILENAME} thing" - << "/tmp/KeePassXC.kdbx.ext" - << "some KeePassXC.kdbx thing"; + QTest::newRow("{DB_FILENAME} substitution with multiple extensions") + << "some {DB_FILENAME} thing" << "/tmp/KeePassXC.kdbx.ext" << "some KeePassXC.kdbx thing"; // Not relevant right now, added test anyway - QTest::newRow("There should be no substitution loops") << "{DB_FILENAME}" - << "{TIME:'{DB_FILENAME}'}.ext" - << "{DB_FILENAME}"; + QTest::newRow("There should be no substitution loops") + << "{DB_FILENAME}" << "{TIME:'{DB_FILENAME}'}.ext" << "{TIME:'{DB_FILENAME}'}"; } void TestTools::testBackupFilePatternSubstitution() @@ -187,8 +193,8 @@ void TestTools::testEscapeRegex_data() } QTest::newRow("Regular characters should not be escaped") << all_regular_characters << all_regular_characters; - QTest::newRow("Special characters should be escaped") << R"(.^$*+-?()[]{}|\)" - << R"(\.\^\$\*\+\-\?\(\)\[\]\{\}\|\\)"; + QTest::newRow("Special characters should be escaped") + << R"(.^$*+-?()[]{}|\)" << R"(\.\^\$\*\+\-\?\(\)\[\]\{\}\|\\)"; QTest::newRow("Null character") << QString::fromLatin1("ab\0c", 4) << "ab\\0c"; } @@ -250,23 +256,17 @@ void TestTools::testConvertToRegex_data() void TestTools::testArrayContainsValues() { - const auto values = QStringList() << "first" - << "second" - << "third"; + const auto values = QStringList() << "first" << "second" << "third"; // One missing - const auto result1 = Tools::getMissingValuesFromList(values, - QStringList() << "first" - << "second" - << "none"); + const auto result1 = + Tools::getMissingValuesFromList(values, QStringList() << "first" << "second" << "none"); QCOMPARE(result1.length(), 1); QCOMPARE(result1.first(), QString("none")); // All found - const auto result2 = Tools::getMissingValuesFromList(values, - QStringList() << "first" - << "second" - << "third"); + const auto result2 = + Tools::getMissingValuesFromList(values, QStringList() << "first" << "second" << "third"); QCOMPARE(result2.length(), 0); // None are found @@ -274,3 +274,157 @@ void TestTools::testArrayContainsValues() const auto result3 = Tools::getMissingValuesFromList(numberValues, QList({6, 7, 8})); QCOMPARE(result3.length(), 3); } + +void TestTools::testMimeTypes() +{ + const QStringList TextMimeTypes = { + "text/plain", // Plain text + "text/css", // CSS stylesheets + "text/javascript", // JavaScript files + "text/xml", // XML documents + "text/rtf", // Rich Text Format + "text/vcard", // vCard files + "text/tab-separated-values", // Tab-separated values + "application/json", // JSON data + "application/xml", // XML data + "application/soap+xml", // SOAP messages + "application/x-yaml", // YAML data + "application/protobuf", // Protocol Buffers + }; + + const QStringList ImageMimeTypes = { + "image/jpeg", // JPEG images + "image/png", // PNG images + "image/gif", // GIF images + "image/bmp", // BMP images + "image/webp", // WEBP images + "image/svg+xml" // SVG images + }; + + const QStringList UnknownMimeTypes = { + "audio/mpeg", // MPEG audio files + "video/mp4", // MP4 video files + "application/pdf", // PDF documents + "application/zip", // ZIP archives + "application/x-tar", // TAR archives + "application/x-rar-compressed", // RAR archives + "application/x-7z-compressed", // 7z archives + "application/x-shockwave-flash", // Adobe Flash files + "application/vnd.ms-excel", // Microsoft Excel files + "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", // Microsoft Excel (OpenXML) files + "application/vnd.ms-powerpoint", // Microsoft PowerPoint files + "application/vnd.openxmlformats-officedocument.presentationml.presentation", // Microsoft PowerPoint (OpenXML) + // files + "application/msword", // Microsoft Word files + "application/vnd.openxmlformats-officedocument.wordprocessingml.document", // Microsoft Word (OpenXML) files + "application/vnd.oasis.opendocument.text", // OpenDocument Text + "application/vnd.oasis.opendocument.spreadsheet", // OpenDocument Spreadsheet + "application/vnd.oasis.opendocument.presentation", // OpenDocument Presentation + "application/x-httpd-php", // PHP files + "application/x-perl", // Perl scripts + "application/x-python", // Python scripts + "application/x-ruby", // Ruby scripts + "application/x-shellscript", // Shell scripts + }; + + QCOMPARE(Tools::toMimeType("text/html"), Tools::MimeType::Html); + QCOMPARE(Tools::toMimeType("text/markdown"), Tools::MimeType::Markdown); + + for (const auto& mime : TextMimeTypes) { + QCOMPARE(Tools::toMimeType(mime), Tools::MimeType::PlainText); + } + + for (const auto& mime : ImageMimeTypes) { + QCOMPARE(Tools::toMimeType(mime), Tools::MimeType::Image); + } + + for (const auto& mime : UnknownMimeTypes) { + QCOMPARE(Tools::toMimeType(mime), Tools::MimeType::Unknown); + } +} + +void TestTools::testGetMimeType() +{ + const QStringList Text = {"0x42", ""}; + + for (const auto& text : Text) { + QCOMPARE(Tools::getMimeType(text.toUtf8()), Tools::MimeType::PlainText); + } + + const QByteArrayList ImageHeaders = { + // JPEG: starts with 0xFF 0xD8 0xFF (Start of Image marker) + QByteArray::fromHex("FFD8FF"), + // PNG: starts with 0x89 0x50 0x4E 0x47 0D 0A 1A 0A (PNG signature) + QByteArray::fromHex("89504E470D0A1A0A"), + // GIF87a: original GIF format (1987 standard) + QByteArray("GIF87a"), + // GIF89a: extended GIF format (1989, supports animation, transparency, etc.) + QByteArray("GIF89a"), + }; + + for (const auto& image : ImageHeaders) { + QCOMPARE(Tools::getMimeType(image), Tools::MimeType::Image); + } + + const QByteArrayList UnknownHeaders = { + // MP3: typically starts with ID3 tag (ID3v2) + QByteArray("ID3"), + // MP4: usually starts with a 'ftyp' box (ISO base media file format) + // Common major brands: isom, mp42, avc1, etc. + QByteArray::fromHex("000000186674797069736F6D"), // size + 'ftyp' + 'isom' + // PDF: starts with "%PDF-" followed by version (e.g., %PDF-1.7) + QByteArray("%PDF-"), + }; + + for (const auto& unknown : UnknownHeaders) { + QCOMPARE(Tools::getMimeType(unknown), Tools::MimeType::Unknown); + } +} + +void TestTools::testGetMimeTypeByFileInfo() +{ + const QStringList Text = {"test.txt", "test.csv", "test.xml", "test.json"}; + + for (const auto& text : Text) { + QCOMPARE(Tools::getMimeType(QFileInfo(text)), Tools::MimeType::PlainText); + } + + const QStringList Images = {"test.jpg", "test.png", "test.bmp", "test.svg"}; + + for (const auto& image : Images) { + QCOMPARE(Tools::getMimeType(QFileInfo(image)), Tools::MimeType::Image); + } + + const QStringList Htmls = {"test.html", "test.htm"}; + + for (const auto& html : Htmls) { + QCOMPARE(Tools::getMimeType(QFileInfo(html)), Tools::MimeType::Html); + } + + const QStringList Markdowns = {"test.md", "test.markdown"}; + + for (const auto& makdown : Markdowns) { + QCOMPARE(Tools::getMimeType(QFileInfo(makdown)), Tools::MimeType::Markdown); + } + + const QStringList UnknownHeaders = {"test.doc", "test.pdf", "test.docx"}; + + for (const auto& unknown : UnknownHeaders) { + QCOMPARE(Tools::getMimeType(unknown), Tools::MimeType::Unknown); + } +} + +void TestTools::testIsTextMimeType() +{ + const auto Text = {Tools::MimeType::PlainText, Tools::MimeType::Html, Tools::MimeType::Markdown}; + + for (const auto& text : Text) { + QVERIFY(Tools::isTextMimeType(text)); + } + + const auto NoText = {Tools::MimeType::Image, Tools::MimeType::Unknown}; + + for (const auto& noText : NoText) { + QVERIFY(!Tools::isTextMimeType(noText)); + } +} diff --git a/tests/TestTools.h b/tests/TestTools.h index e8a44b8b3..728849bd3 100644 --- a/tests/TestTools.h +++ b/tests/TestTools.h @@ -18,7 +18,7 @@ #ifndef KEEPASSX_TESTTOOLS_H #define KEEPASSX_TESTTOOLS_H -#include "core/Tools.h" +#include class TestTools : public QObject { @@ -37,6 +37,10 @@ private slots: void testConvertToRegex(); void testConvertToRegex_data(); void testArrayContainsValues(); + void testMimeTypes(); + void testGetMimeType(); + void testGetMimeTypeByFileInfo(); + void testIsTextMimeType(); }; #endif // KEEPASSX_TESTTOOLS_H diff --git a/tests/TestTotp.cpp b/tests/TestTotp.cpp index f2bb3d47a..13aaf9a2d 100644 --- a/tests/TestTotp.cpp +++ b/tests/TestTotp.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2017 Weslly Honorato <weslly@protonmail.com> + * Copyright (C) 2017 Weslly Honorato * Copyright (C) 2017 KeePassXC Team * * This program is free software: you can redistribute it and/or modify @@ -40,11 +40,11 @@ void TestTotp::testParseSecret() auto settings = Totp::parseSettings(secret); QVERIFY(!settings.isNull()); QCOMPARE(settings->key, QString("HXDMVJECJJWSRB3HWIZR4IFUGFTMXBOZ")); - QCOMPARE(settings->custom, false); QCOMPARE(settings->format, Totp::StorageFormat::OTPURL); QCOMPARE(settings->digits, 6u); QCOMPARE(settings->step, 30u); QCOMPARE(settings->algorithm, Totp::Algorithm::Sha1); + QCOMPARE(Totp::hasCustomSettings(settings), false); // OTP URL with non-default hash type secret = "otpauth://totp/" @@ -53,11 +53,11 @@ void TestTotp::testParseSecret() settings = Totp::parseSettings(secret); QVERIFY(!settings.isNull()); QCOMPARE(settings->key, QString("HXDMVJECJJWSRB3HWIZR4IFUGFTMXBOZ")); - QCOMPARE(settings->custom, true); QCOMPARE(settings->format, Totp::StorageFormat::OTPURL); QCOMPARE(settings->digits, 6u); QCOMPARE(settings->step, 30u); QCOMPARE(settings->algorithm, Totp::Algorithm::Sha512); + QCOMPARE(Totp::hasCustomSettings(settings), true); // Max TOTP step of 24-hours secret.replace("period=30", "period=90000"); @@ -70,33 +70,33 @@ void TestTotp::testParseSecret() settings = Totp::parseSettings(secret); QVERIFY(!settings.isNull()); QCOMPARE(settings->key, QString("HXDMVJECJJWSRBY=")); - QCOMPARE(settings->custom, true); QCOMPARE(settings->format, Totp::StorageFormat::KEEOTP); QCOMPARE(settings->digits, 8u); QCOMPARE(settings->step, 25u); QCOMPARE(settings->algorithm, Totp::Algorithm::Sha256); + QCOMPARE(Totp::hasCustomSettings(settings), true); // Semi-colon delineated "TOTP Settings" secret = "gezdgnbvgy3tqojqgezdgnbvgy3tqojq"; settings = Totp::parseSettings("30;8", secret); QVERIFY(!settings.isNull()); QCOMPARE(settings->key, QString("gezdgnbvgy3tqojqgezdgnbvgy3tqojq")); - QCOMPARE(settings->custom, true); QCOMPARE(settings->format, Totp::StorageFormat::LEGACY); QCOMPARE(settings->digits, 8u); QCOMPARE(settings->step, 30u); QCOMPARE(settings->algorithm, Totp::Algorithm::Sha1); + QCOMPARE(Totp::hasCustomSettings(settings), true); // Bare secret (no "TOTP Settings" attribute) secret = "gezdgnbvgy3tqojqgezdgnbvgy3tqojq"; settings = Totp::parseSettings("", secret); QVERIFY(!settings.isNull()); QCOMPARE(settings->key, QString("gezdgnbvgy3tqojqgezdgnbvgy3tqojq")); - QCOMPARE(settings->custom, false); QCOMPARE(settings->format, Totp::StorageFormat::LEGACY); QCOMPARE(settings->digits, 6u); QCOMPARE(settings->step, 30u); QCOMPARE(settings->algorithm, Totp::Algorithm::Sha1); + QCOMPARE(Totp::hasCustomSettings(settings), false); // Blank settings (expected failure) settings = Totp::parseSettings("", ""); @@ -115,28 +115,35 @@ void TestTotp::testTotpCode() // Test 6 digit TOTP (default) quint64 time = 1234567890; - QCOMPARE(Totp::generateTotp(settings, time), QString("005924")); + QCOMPARE(Totp::generateTotp(settings, nullptr, time), QString("005924")); time = 1111111109; - QCOMPARE(Totp::generateTotp(settings, time), QString("081804")); + QCOMPARE(Totp::generateTotp(settings, nullptr, time), QString("081804")); // Test 8 digit TOTP (custom) settings->digits = 8; - settings->custom = true; time = 1111111111; - QCOMPARE(Totp::generateTotp(settings, time), QString("14050471")); + QCOMPARE(Totp::generateTotp(settings, nullptr, time), QString("14050471")); time = 2000000000; - QCOMPARE(Totp::generateTotp(settings, time), QString("69279037")); + QCOMPARE(Totp::generateTotp(settings, nullptr, time), QString("69279037")); } void TestTotp::testSteamTotp() { + // Legacy parsing + auto settings = Totp::parseSettings("30;S", "63BEDWCQZKTQWPESARIERL5DTTQFCJTK"); + QCOMPARE(settings->key, QString("63BEDWCQZKTQWPESARIERL5DTTQFCJTK")); + QCOMPARE(settings->encoder.shortName, Totp::STEAM_SHORTNAME); + QCOMPARE(settings->format, Totp::StorageFormat::LEGACY); + QCOMPARE(settings->digits, Totp::STEAM_DIGITS); + QCOMPARE(settings->step, 30u); + // OTP URL Parsing QString secret = "otpauth://totp/" "test:test@example.com?secret=63BEDWCQZKTQWPESARIERL5DTTQFCJTK&issuer=Valve&algorithm=" "SHA1&digits=5&period=30&encoder=steam"; - auto settings = Totp::parseSettings(secret); + settings = Totp::parseSettings(secret); QCOMPARE(settings->key, QString("63BEDWCQZKTQWPESARIERL5DTTQFCJTK")); QCOMPARE(settings->encoder.shortName, Totp::STEAM_SHORTNAME); @@ -148,9 +155,9 @@ void TestTotp::testSteamTotp() // Steam mobile app with a throw-away steam account. The above secret was extracted // from the Steam app's data for use in testing here. quint64 time = 1511200518; - QCOMPARE(Totp::generateTotp(settings, time), QString("FR8RV")); + QCOMPARE(Totp::generateTotp(settings, nullptr, time), QString("FR8RV")); time = 1511200714; - QCOMPARE(Totp::generateTotp(settings, time), QString("9P3VP")); + QCOMPARE(Totp::generateTotp(settings, nullptr, time), QString("9P3VP")); } void TestTotp::testEntryHistory() @@ -177,3 +184,39 @@ void TestTotp::testEntryHistory() QVERIFY(!entry.hasTotp()); QCOMPARE(entry.historyItems().size(), 3); } + +void TestTotp::testKeePass2() +{ + Entry entry; + auto attr = entry.attributes(); + + // Default settings + attr->set("TimeOtp-Secret-Base32", "GEZDGNBVGY3TQOJQGEZDGNBVGY3TQOJQ"); + + auto settings = entry.totpSettings(); + QVERIFY(settings); + QCOMPARE(settings->key, QString("GEZDGNBVGY3TQOJQGEZDGNBVGY3TQOJQ")); + QCOMPARE(settings->algorithm, Totp::Algorithm::Sha1); + QCOMPARE(settings->digits, 6u); + QCOMPARE(settings->step, 30u); + QCOMPARE(Totp::hasCustomSettings(settings), false); + + // Custom settings + attr->set("TimeOtp-Algorithm", "HMAC-SHA-256"); + attr->set("TimeOtp-Length", "8"); + + settings = entry.totpSettings(); + QVERIFY(settings); + QCOMPARE(settings->key, QString("GEZDGNBVGY3TQOJQGEZDGNBVGY3TQOJQ")); + QCOMPARE(settings->algorithm, Totp::Algorithm::Sha256); + QCOMPARE(settings->digits, 8u); + QCOMPARE(settings->step, 30u); + QCOMPARE(Totp::hasCustomSettings(settings), true); + + // Base64 and other encodings are not supported + attr->remove("TimeOtp-Secret-Base32"); + attr->set("TimeOtp-Secret-Base64", "GEZDGNBVGY3TQOJQGEZDGNBVGY3TQOJQ"); + + settings = entry.totpSettings(); + QVERIFY(!settings); +} diff --git a/tests/TestTotp.h b/tests/TestTotp.h index 92fa7a0e1..f2e696734 100644 --- a/tests/TestTotp.h +++ b/tests/TestTotp.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2017 Weslly Honorato <weslly@protonmail.com> + * Copyright (C) 2017 Weslly Honorato * Copyright (C) 2017 KeePassXC Team * * This program is free software: you can redistribute it and/or modify @@ -31,6 +31,7 @@ private slots: void testTotpCode(); void testSteamTotp(); void testEntryHistory(); + void testKeePass2(); }; #endif // KEEPASSX_TESTTOTP_H diff --git a/tests/TestUpdateCheck.cpp b/tests/TestUpdateCheck.cpp index df2643fad..f89757ea6 100644 --- a/tests/TestUpdateCheck.cpp +++ b/tests/TestUpdateCheck.cpp @@ -17,7 +17,7 @@ #include "TestUpdateCheck.h" #include "crypto/Crypto.h" -#include "updatecheck/UpdateChecker.h" +#include "networking/UpdateChecker.h" #include diff --git a/tests/TestUrlTools.cpp b/tests/TestUrlTools.cpp index bc6f3546b..ae059d228 100644 --- a/tests/TestUrlTools.cpp +++ b/tests/TestUrlTools.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2024 KeePassXC Team + * Copyright (C) 2025 KeePassXC Team * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -43,7 +43,6 @@ void TestUrlTools::testTopLevelDomain() {QString("https://192.168.0.1:8000"), QString("192.168.0.1")}, {QString("https://www.nic.ar"), QString("ar")}, {QString("https://no.no.no"), QString("no")}, - {QString("https://www.blogspot.com.ar"), QString("blogspot.com.ar")}, // blogspot.com.ar is a TLD {QString("https://jap.an.ide.kyoto.jp"), QString("ide.kyoto.jp")}, // ide.kyoto.jp is a TLD {QString("ar"), QString("ar")}, }; @@ -61,7 +60,6 @@ void TestUrlTools::testTopLevelDomain() {QString("https://192.168.0.1"), QString("192.168.0.1")}, {QString("https://192.168.0.1:8000"), QString("192.168.0.1")}, {QString("https://www.nic.ar"), QString("nic.ar")}, - {QString("https://www.blogspot.com.ar"), QString("www.blogspot.com.ar")}, // blogspot.com.ar is a TLD {QString("https://www.arpa"), QString("www.arpa")}, {QString("https://jap.an.ide.kyoto.jp"), QString("an.ide.kyoto.jp")}, // ide.kyoto.jp is a TLD {QString("https://kobe.jp"), QString("kobe.jp")}, @@ -136,6 +134,41 @@ void TestUrlTools::testIsUrlValid() } } +void TestUrlTools::testIsUrlValidWithLooseComparison() +{ + QHash urls; + urls[""] = true; + urls["\"https://github.com/login\""] = true; + urls["https://*.github.com/"] = true; + urls["*.github.com"] = true; + urls["https://*.com"] = false; + urls["https://*.computer.com"] = true; // TLD in domain (com) should not affect + urls["\"\""] = false; + urls["\"*.example.com\""] = false; + urls["http://*"] = false; + urls["*"] = false; + urls["****"] = false; + urls["*.co.jp"] = false; + urls["*.com"] = false; + urls["*.computer.com"] = true; + urls["*.computer.com/*com"] = true; // TLD in path should not affect this + urls["*com"] = false; + urls["*.com/"] = false; + urls["*.com/*"] = false; + urls["**.com/**"] = false; + urls["*.*"] = false; + urls["https://example.*"] = false; + urls["https://*.example.*"] = false; + urls["https://example.c*"] = false; + urls["https://myowndomain:8000"] = true; + + QHashIterator i(urls); + while (i.hasNext()) { + i.next(); + QCOMPARE(urlTools()->isUrlValid(i.key(), true), i.value()); + } +} + void TestUrlTools::testDomainHasIllegalCharacters() { QVERIFY(!urlTools()->domainHasIllegalCharacters("example.com")); diff --git a/tests/TestUrlTools.h b/tests/TestUrlTools.h index 74e91c174..c2ba770b8 100644 --- a/tests/TestUrlTools.h +++ b/tests/TestUrlTools.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2024 KeePassXC Team + * Copyright (C) 2025 KeePassXC Team * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -18,7 +18,7 @@ #ifndef KEEPASSXC_TESTURLTOOLS_H #define KEEPASSXC_TESTURLTOOLS_H -#include "core/UrlTools.h" +#include "gui/UrlTools.h" #include #include @@ -34,6 +34,7 @@ private slots: void testIsIpAddress(); void testIsUrlIdentical(); void testIsUrlValid(); + void testIsUrlValidWithLooseComparison(); void testDomainHasIllegalCharacters(); private: diff --git a/tests/TestYkChallengeResponseKey.cpp b/tests/TestYkChallengeResponseKey.cpp index c1064518e..02a0b5bea 100644 --- a/tests/TestYkChallengeResponseKey.cpp +++ b/tests/TestYkChallengeResponseKey.cpp @@ -24,6 +24,7 @@ #include "keys/ChallengeResponseKey.h" #include +#include #include #include @@ -45,9 +46,12 @@ void TestYubiKeyChallengeResponse::testDetectDevices() // Look at the information retrieved from the key(s) const auto foundKeys = YubiKey::instance()->foundKeys(); + QRegularExpression exp{"\\w+\\s+\\[\\d+\\]\\s+-\\s+Slot\\s+\\d"}; + for (auto i = foundKeys.cbegin(); i != foundKeys.cend(); ++i) { const auto& displayName = i.value(); - QVERIFY(displayName.contains("Challenge-Response - Slot") || displayName.contains("Configured Slot -")); + auto match = exp.match(displayName); + QVERIFY(match.hasMatch()); QVERIFY(displayName.contains(QString::number(i.key().first))); QVERIFY(displayName.contains(QString::number(i.key().second))); } diff --git a/tests/data/1PasswordExport.1pux b/tests/data/1PasswordExport.1pux index 509d7d07b..12cfcb6c6 100644 Binary files a/tests/data/1PasswordExport.1pux and b/tests/data/1PasswordExport.1pux differ diff --git a/tests/data/SyncDatabase.kdbx b/tests/data/SyncDatabase.kdbx new file mode 100644 index 000000000..1a8ad9375 Binary files /dev/null and b/tests/data/SyncDatabase.kdbx differ diff --git a/tests/data/SyncDatabaseDifferentPassword.kdbx b/tests/data/SyncDatabaseDifferentPassword.kdbx new file mode 100644 index 000000000..372ead78c Binary files /dev/null and b/tests/data/SyncDatabaseDifferentPassword.kdbx differ diff --git a/tests/data/bitwarden_passkey_export.json b/tests/data/bitwarden_passkey_export.json new file mode 100644 index 000000000..0044fc334 --- /dev/null +++ b/tests/data/bitwarden_passkey_export.json @@ -0,0 +1,49 @@ +{ + "encrypted": false, + "folders": [], + "items": [ + { + "passwordHistory": null, + "revisionDate": "2024-10-23T16:38:08.870Z", + "creationDate": "2024-10-23T16:38:08.606Z", + "deletedDate": null, + "id": "a8e579f0-98c2-4ac9-a126-b212011225f8", + "organizationId": null, + "folderId": null, + "type": 1, + "reprompt": 0, + "name": "webauthn.io", + "notes": null, + "favorite": false, + "login": { + "fido2Credentials": [ + { + "credentialId": "a3e15f8b-27c1-42ae-90cf-a615ad87854f", + "keyType": "public-key", + "keyAlgorithm": "ECDSA", + "keyCurve": "P-256", + "keyValue": "MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgmr4GQQjerojFuf0ZouOuUllMvAwxZSZAfB6gwDYcLiehRANCAAT0WR5zVSp6ieusvjkLkzaGc7fjGBmwpiuLPxR_d-ZjqMI9L2DKh-takp6wGt2x0n4jzr1KA352NZg0vjZX9CHh", + "rpId": "webauthn.io", + "userHandle": "aTFtdmFnOHYtS2dxVEJ0by1rSFpLWGg0enlTVC1iUVJReDZ5czJXa3c2aw", + "userName": "KPXC_BITWARDEN", + "counter": "0", + "rpName": "webauthn.io", + "userDisplayName": "KPXC_BITWARDEN", + "discoverable": "true", + "creationDate": "2024-10-23T16:38:08.617Z" + } + ], + "uris": [ + { + "match": null, + "uri": "https://webauthn.io/" + } + ], + "username": "KPXC_BITWARDEN", + "password": null, + "totp": null + }, + "collectionIds": null + } + ] +} \ No newline at end of file diff --git a/tests/data/protonpass_export.json b/tests/data/protonpass_export.json new file mode 100644 index 000000000..ef8235218 --- /dev/null +++ b/tests/data/protonpass_export.json @@ -0,0 +1,173 @@ +{ + "version": "1.21.2", + "userId": "USER_ID", + "encrypted": false, + "vaults": { + "VAULT_A": { + "name": "Personal", + "description": "Personal vault", + "display": { + "color": 0, + "icon": 0 + }, + "items": [ + { + "itemId": "yZENmDjtmZGODNy3Q_CZiPAF_IgINq8w-R-qazrOh-Nt9YJeVF3gu07ovzDS4jhYHoMdOebTw5JkYPGgIL1mwQ==", + "shareId": "SN5uWo4WZF2uT5wIDqtbdpkjuxCbNTOIdf-JQ_DYZcKYKURHiZB5csS1a1p9lklvju9ni42l08IKzwQG0B2ySg==", + "data": { + "metadata": { + "name": "Test Login", + "note": "My login secure note.", + "itemUuid": "e8ee1a0c" + }, + "extraFields": [ + { + "fieldName": "non-hidden field", + "type": "text", + "data": { + "content": "non-hidden field content" + } + }, + { + "fieldName": "hidden field", + "type": "hidden", + "data": { + "content": "hidden field content" + } + }, + { + "fieldName": "second 2fa secret", + "type": "totp", + "data": { + "totpUri": "TOTPCODE" + } + } + ], + "type": "login", + "content": { + "itemEmail": "Email", + "password": "Password", + "urls": [ + "https://example.com/", + "https://example2.com/" + ], + "totpUri": "otpauth://totp/Test%20Login%20-%20Personal%20Vault:Username?issuer=Test%20Login%20-%20Personal%20Vault&secret=TOTPCODE&algorithm=SHA1&digits=6&period=30", + "passkeys": [], + "itemUsername": "Username" + } + }, + "state": 1, + "aliasEmail": null, + "contentFormatVersion": 1, + "createTime": 1689182868, + "modifyTime": 1689182868, + "pinned": true + }, + { + "itemId": "xqq_Bh8RxNMBerkiMvRdH427yswZznjYwps-f6C5D8tmKiPgMxCSPNz1BOd4nRJ309gciDiPhXcCVWOyfJ66ZA==", + "shareId": "SN5uWo4WZF2uT5wIDqtbdpkjuxCbNTOIdf-JQ_DYZcKYKURHiZB5csS1a1p9lklvju9ni42l08IKzwQG0B2ySg==", + "data": { + "metadata": { + "name": "My Secure Note", + "note": "Secure note contents.", + "itemUuid": "ad618070" + }, + "extraFields": [], + "type": "note", + "content": {} + }, + "state": 1, + "aliasEmail": null, + "contentFormatVersion": 1, + "createTime": 1689182908, + "modifyTime": 1689182908, + "pinned": false + }, + { + "itemId": "ZmGzd-HNQYTr6wmfWlSfiStXQLqGic_PYB2Q2T_hmuRM2JIA4pKAPJcmFafxJrDpXxLZ2EPjgD6Noc9a0U6AVQ==", + "shareId": "SN5uWo4WZF2uT5wIDqtbdpkjuxCbNTOIdf-JQ_DYZcKYKURHiZB5csS1a1p9lklvju9ni42l08IKzwQG0B2ySg==", + "data": { + "metadata": { + "name": "Test Card", + "note": "Credit Card Note", + "itemUuid": "d8f45370" + }, + "extraFields": [], + "type": "creditCard", + "content": { + "cardholderName": "Test name", + "cardType": 0, + "number": "1234222233334444", + "verificationNumber": "333", + "expirationDate": "2025-01", + "pin": "1234" + } + }, + "state": 1, + "aliasEmail": null, + "contentFormatVersion": 1, + "createTime": 1691001643, + "modifyTime": 1691001643, + "pinned": true + }, + { + "itemId": "xqq_Bh8RxNMBerkiMvRdH427yswZznjYwps-f6C5D8tmKiPgMxCSPNz1BOd4nRJ309gciDiPhXcCVWOyfJ66ZA==", + "shareId": "SN5uWo4WZF2uT5wIDqtbdpkjuxCbNTOIdf-JQ_DYZcKYKURHiZB5csS1a1p9lklvju9ni42l08IKzwQG0B2ySg==", + "data": { + "metadata": { + "name": "My Deleted Note", + "note": "Secure note contents.", + "itemUuid": "ad618070" + }, + "extraFields": [], + "type": "note", + "content": {} + }, + "state": 2, + "aliasEmail": null, + "contentFormatVersion": 1, + "createTime": 1689182908, + "modifyTime": 1689182908, + "pinned": false + } + ] + }, + "VAULT_B": { + "name": "Test", + "description": "", + "display": { + "color": 4, + "icon": 2 + }, + "items": [ + { + "itemId": "U_J8-eUR15sC-PjUhjVcixDcayhjGuoerUZCr560RlAi0ZjBNkSaSKAytVzZn4E0hiFX1_y4qZbUetl6jO3aJw==", + "shareId": "OJz-4MnPqAuYnyemhctcGDlSLJrzsTnf2FnFSwxh1QP_oth9xyGDc2ZAqCv5FnqkVgTNHT5aPj62zcekNemfNw==", + "data": { + "metadata": { + "name": "Other vault login", + "note": "", + "itemUuid": "f3429d44" + }, + "extraFields": [], + "type": "login", + "content": { + "itemEmail": "other vault username", + "password": "other vault password", + "urls": [], + "totpUri": "JBSWY3DPEHPK3PXP", + "passkeys": [], + "itemUsername": "" + } + }, + "state": 1, + "aliasEmail": null, + "contentFormatVersion": 1, + "createTime": 1689182949, + "modifyTime": 1689182949, + "pinned": false + } + ] + } + } +} \ No newline at end of file diff --git a/tests/data/wordlists/bad_wordlist_with_duplicate_entries.wordlist b/tests/data/wordlists/bad_wordlist_with_duplicate_entries.wordlist new file mode 100644 index 000000000..50246c96a --- /dev/null +++ b/tests/data/wordlists/bad_wordlist_with_duplicate_entries.wordlist @@ -0,0 +1,4 @@ +abacus +abdomen +abdominal +abdominal diff --git a/tests/gui/CMakeLists.txt b/tests/gui/CMakeLists.txt index 3264da515..30f255778 100644 --- a/tests/gui/CMakeLists.txt +++ b/tests/gui/CMakeLists.txt @@ -15,9 +15,13 @@ include_directories(${CMAKE_CURRENT_SOURCE_DIR}/..) -add_unit_test(NAME testgui SOURCES TestGui.cpp ../util/TemporaryFile.cpp LIBS ${TEST_LIBRARIES}) +add_unit_test(NAME testgui SOURCES TestGui.cpp ../util/TemporaryFile.cpp ../mock/MockRemoteProcess.cpp LIBS ${TEST_LIBRARIES}) add_unit_test(NAME testguipixmaps SOURCES TestGuiPixmaps.cpp LIBS ${TEST_LIBRARIES}) +file(GLOB_RECURSE ATTACHMENTS_TEST_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/attachments/*.cpp) +add_unit_test(NAME testguiattachments SOURCES ${ATTACHMENTS_TEST_SOURCES} LIBS ${TEST_LIBRARIES}) +include_directories(testguiattachments PRIVATE ${PROJECT_SOURCE_DIR}/src/gui/entry) + if(WITH_XC_BROWSER) add_unit_test(NAME testguibrowser SOURCES TestGuiBrowser.cpp ../util/TemporaryFile.cpp LIBS ${TEST_LIBRARIES}) endif() diff --git a/tests/gui/TestGui.cpp b/tests/gui/TestGui.cpp index f65c42940..9011d445c 100644 --- a/tests/gui/TestGui.cpp +++ b/tests/gui/TestGui.cpp @@ -21,12 +21,16 @@ #include #include +#include +#include +#include #include #include #include #include #include #include +#include #include #include @@ -34,6 +38,7 @@ #include "core/PasswordHealth.h" #include "core/Tools.h" #include "crypto/Crypto.h" +#include "gui/ActionCollection.h" #include "gui/ApplicationSettingsWidget.h" #include "gui/CategoryListWidget.h" #include "gui/CloneDialog.h" @@ -44,19 +49,23 @@ #include "gui/PasswordGeneratorWidget.h" #include "gui/PasswordWidget.h" #include "gui/SearchWidget.h" +#include "gui/ShortcutSettingsPage.h" #include "gui/TotpDialog.h" #include "gui/TotpSetupDialog.h" #include "gui/databasekey/KeyFileEditWidget.h" #include "gui/databasekey/PasswordEditWidget.h" #include "gui/dbsettings/DatabaseSettingsDialog.h" +#include "gui/dbsettings/DatabaseSettingsWidgetEncryption.h" #include "gui/entry/EditEntryWidget.h" #include "gui/entry/EntryView.h" #include "gui/group/EditGroupWidget.h" #include "gui/group/GroupModel.h" #include "gui/group/GroupView.h" +#include "gui/remote/RemoteHandler.h" #include "gui/tag/TagsEdit.h" #include "gui/wizard/NewDatabaseWizard.h" #include "keys/FileKey.h" +#include "mock/MockRemoteProcess.h" #define TEST_MODAL_NO_WAIT(TEST_CODE) \ bool dialogFinished = false; \ @@ -68,10 +77,8 @@ int main(int argc, char* argv[]) { -#if QT_VERSION >= QT_VERSION_CHECK(5, 6, 0) QApplication::setAttribute(Qt::AA_EnableHighDpiScaling); QGuiApplication::setAttribute(Qt::AA_UseHighDpiPixmaps); -#endif Application app(argc, argv); app.setApplicationName("KeePassXC"); app.setApplicationVersion(KEEPASSXC_VERSION); @@ -87,7 +94,10 @@ int main(int argc, char* argv[]) void TestGui::initTestCase() { QVERIFY(Crypto::init()); - Config::createTempFileInstance(); + + // Create temporary config file + Config::createConfigFromFile(TemporaryFile::createTempConfigFile(), {}); + QLocale::setDefault(QLocale::c()); Application::bootstrap(); @@ -155,14 +165,13 @@ void TestGui::init() // Every test ends with closing the temp database without saving void TestGui::cleanup() { - // DO NOT save the database - m_db->markAsClean(); - MessageBox::setNextAnswer(MessageBox::No); - triggerAction("actionDatabaseClose"); - QApplication::processEvents(); - MessageBox::setNextAnswer(MessageBox::NoButton); - - if (m_dbWidget) { + if (m_tabWidget->isVisible()) { + // DO NOT save the database + m_db->markAsClean(); + MessageBox::setNextAnswer(MessageBox::No); + triggerAction("actionDatabaseClose"); + QApplication::processEvents(); + MessageBox::setNextAnswer(MessageBox::NoButton); delete m_dbWidget; } } @@ -348,8 +357,9 @@ void TestGui::testMergeDatabase() fileDialog()->setNextFileName(QString(KEEPASSX_TEST_DATA_DIR).append("/MergeDatabase.kdbx")); triggerAction("actionDatabaseMerge"); - QTRY_COMPARE(QApplication::focusWidget()->objectName(), QString("passwordEdit")); auto* editPasswordMerge = QApplication::focusWidget(); + QVERIFY(editPasswordMerge); + QTRY_COMPARE(editPasswordMerge->objectName(), QString("passwordEdit")); QVERIFY(editPasswordMerge->isVisible()); QTest::keyClicks(editPasswordMerge, "a"); @@ -368,6 +378,158 @@ void TestGui::testMergeDatabase() QCOMPARE(m_db->rootGroup()->findChildByName("General")->entries().size(), 1); } +void TestGui::prepareAndTriggerRemoteSync() +{ + // create remote settings in settings dialog + triggerAction("actionDatabaseSettings"); + + auto dbSettingsDialog = m_dbWidget->findChild("databaseSettingsDialog"); + QVERIFY(dbSettingsDialog); + dbSettingsDialog->showRemoteSettings(); + + auto name = "testCommand"; + auto nameEdit = dbSettingsDialog->findChild("nameLineEdit"); + QVERIFY(nameEdit); + QVERIFY(nameEdit->isVisible()); + nameEdit->setText(name); + + auto downloadCommandEdit = dbSettingsDialog->findChild("downloadCommand"); + QVERIFY(downloadCommandEdit); + downloadCommandEdit->setText("sftp user@server:Database.kdbx"); + + auto saveSettingsButton = dbSettingsDialog->findChild("saveSettingsButton"); + QVERIFY(saveSettingsButton); + QTest::mouseClick(saveSettingsButton, Qt::LeftButton); + + auto okButton = dbSettingsDialog->findChild("buttonBox")->button(QDialogButtonBox::Ok); + QVERIFY(okButton); + QTest::mouseClick(okButton, Qt::LeftButton); + + QTRY_COMPARE(m_dbWidget->getRemoteParams().size(), 1); + + // Show menu to trigger populating with remote sync action + auto menuRemoteSync = m_mainWindow->findChild("menuRemoteSync"); + QVERIFY(menuRemoteSync); + menuRemoteSync->popup({0, 0}); + QApplication::processEvents(); + menuRemoteSync->close(); + + // Trigger the remote sync action + for (const auto remoteAction : menuRemoteSync->actions()) { + if (remoteAction->text() == name) { + remoteAction->trigger(); + return; + } + } + + // If we get here then something didn't work properly + QFAIL("Remote sync action not present in menu."); +} + +void TestGui::testRemoteSyncDatabaseSameKey() +{ + RemoteHandler::setRemoteProcessFunc([](QObject* parent) { + return QScopedPointer( + new MockRemoteProcess(parent, QString(KEEPASSX_TEST_DATA_DIR).append("/SyncDatabase.kdbx"))); + }); + QSignalSpy dbSyncSpy(m_dbWidget.data(), &DatabaseWidget::databaseSyncCompleted); + prepareAndTriggerRemoteSync(); + QTRY_COMPARE(dbSyncSpy.count(), 1); + + m_db = m_tabWidget->currentDatabaseWidget()->database(); + + // there are seven child groups of the root group + QCOMPARE(m_db->rootGroup()->children().size(), 7); + // the merged group should contain an entry + QCOMPARE(m_db->rootGroup()->children().at(6)->entries().size(), 1); + // the General group contains one entry merged from the other db + QCOMPARE(m_db->rootGroup()->findChildByName("General")->entries().size(), 1); +} + +void TestGui::testRemoteSyncDatabaseRequiresPassword() +{ + RemoteHandler::setRemoteProcessFunc([](QObject* parent) { + return QScopedPointer(new MockRemoteProcess( + parent, QString(KEEPASSX_TEST_DATA_DIR).append("/SyncDatabaseDifferentPassword.kdbx"))); + }); + QSignalSpy dbSyncSpy(m_dbWidget.data(), &DatabaseWidget::databaseSyncCompleted); + prepareAndTriggerRemoteSync(); + + // need to process more events as opening with the same key did not work and more events have been fired + QApplication::processEvents(QEventLoop::WaitForMoreEvents); + + auto* editPasswordSync = QApplication::focusWidget(); + QVERIFY(editPasswordSync); + QTRY_COMPARE(editPasswordSync->objectName(), QString("passwordEdit")); + QVERIFY(editPasswordSync->isVisible()); + + QTest::keyClicks(editPasswordSync, "b"); + QTest::keyClick(editPasswordSync, Qt::Key_Enter); + + QTRY_COMPARE(dbSyncSpy.count(), 1); + m_db = m_tabWidget->currentDatabaseWidget()->database(); + + // there are seven child groups of the root group + QCOMPARE(m_db->rootGroup()->children().size(), 7); + // the merged group should contain an entry + QCOMPARE(m_db->rootGroup()->children().at(6)->entries().size(), 1); + // the General group contains one entry merged from the other db + QCOMPARE(m_db->rootGroup()->findChildByName("General")->entries().size(), 1); +} + +void TestGui::testOpenRemoteDatabase() +{ + // close current database + cleanup(); + + QString sourceToSync = "sftp user@server:Database.kdbx"; + RemoteHandler::setRemoteProcessFunc([sourceToSync](QObject* parent) { + return QScopedPointer( + new MockRemoteProcess(parent, QString(KEEPASSX_TEST_DATA_DIR).append("/SyncDatabase.kdbx"))); + }); + auto* openRemoteButton = QApplication::activeWindow()->findChild("buttonImport"); + QVERIFY(openRemoteButton); + QVERIFY(openRemoteButton->isVisible()); + QTest::mouseClick(openRemoteButton, Qt::LeftButton); + QApplication::processEvents(); + + TEST_MODAL_NO_WAIT(ImportWizard * wizard; QTRY_VERIFY(wizard = m_tabWidget->findChild()); + + auto* importTypeList = wizard->currentPage()->findChild("importTypeList"); + QVERIFY(importTypeList); + + for (int i = 0; i < importTypeList->count(); ++i) { + auto item = importTypeList->item(i); + if (item->data(Qt::UserRole) == ImportWizard::IMPORT_REMOTE) { + importTypeList->setCurrentItem(item); + break; + } + } + + auto* downloadCommandEdit = wizard->currentPage()->findChild("downloadCommand"); + QVERIFY(downloadCommandEdit); + QTest::keyClicks(downloadCommandEdit, sourceToSync); + + auto* temporaryDatabaseRadio = + wizard->currentPage()->findChild("temporaryDatabaseRadio"); + QVERIFY(temporaryDatabaseRadio); + QTest::mouseClick(temporaryDatabaseRadio, Qt::LeftButton); + + auto* passwordEdit = wizard->currentPage()->findChild("passwordEdit"); + QVERIFY(passwordEdit); + QTest::keyClicks(passwordEdit, "a"); + QTest::keyClick(passwordEdit, Qt::Key_Enter); + + QApplication::processEvents(); + + QVERIFY(wizard->currentPage()->findChildren().count() > 0); + + QTest::keyClick(passwordEdit, Qt::Key_Enter);); + + // remote database has been opened + QTRY_COMPARE(m_tabWidget->tabText(m_tabWidget->currentIndex()), QString("SyncDatabase [Temporary]")); +} + void TestGui::testAutoreloadDatabase() { config()->set(Config::AutoReloadOnChange, false); @@ -452,7 +614,7 @@ void TestGui::testEditEntry() // Edit the first entry ("Sample Entry") QTest::mouseClick(entryEditWidget, Qt::LeftButton); - QCOMPARE(m_dbWidget->currentMode(), DatabaseWidget::Mode::EditMode); + QCOMPARE(m_dbWidget->currentMode(), DatabaseWidget::Mode::EditEntryMode); auto* editEntryWidget = m_dbWidget->findChild("editEntryWidget"); auto* titleEdit = editEntryWidget->findChild("titleEdit"); QTest::keyClicks(titleEdit, "_test"); @@ -467,13 +629,33 @@ void TestGui::testEditEntry() // Apply the edit QTRY_VERIFY(applyButton->isEnabled()); QTest::mouseClick(applyButton, Qt::LeftButton); - QCOMPARE(m_dbWidget->currentMode(), DatabaseWidget::Mode::EditMode); + QCOMPARE(m_dbWidget->currentMode(), DatabaseWidget::Mode::EditEntryMode); QCOMPARE(entry->title(), QString("Sample Entry_test")); QCOMPARE(entry->historyItems().size(), ++editCount); QVERIFY(!applyButton->isEnabled()); + // Test viewing entry history + auto historyView = editEntryWidget->findChild("historyView"); + auto showButton = editEntryWidget->findChild("showButton"); + QVERIFY(historyView); + editEntryWidget->switchToPage(EditEntryWidget::Page::History); + QApplication::processEvents(); + QVERIFY(historyView->isVisible()); + QVERIFY(!showButton->isEnabled()); + // Select the second row in the history view + historyView->setCurrentIndex(historyView->model()->index(1, 0)); + QVERIFY(showButton->isEnabled()); + QTest::mouseClick(showButton, Qt::LeftButton); + // Verify that the entry history widget is shown + auto entryHistoryWidget = m_dbWidget->findChild("editEntryHistoryWidget"); + QVERIFY(entryHistoryWidget); + QVERIFY(entryHistoryWidget->isVisible()); + QCOMPARE(m_dbWidget->currentMode(), DatabaseWidget::Mode::EditEntryMode); + QTest::keyClick(entryHistoryWidget, Qt::Key_Escape); + QVERIFY(historyView->isVisible()); + // Test the "known bad" checkbox - editEntryWidget->setCurrentPage(1); + editEntryWidget->switchToPage(EditEntryWidget::Page::Advanced); auto excludeReportsCheckBox = editEntryWidget->findChild("excludeReportsCheckBox"); QVERIFY(excludeReportsCheckBox); QCOMPARE(excludeReportsCheckBox->isChecked(), false); @@ -496,7 +678,7 @@ void TestGui::testEditEntry() QCOMPARE(tags->tags().last(), QString("tag 2_is!awesome")); // Test entry colors (simulate choosing a color) - editEntryWidget->setCurrentPage(1); + editEntryWidget->switchToPage(EditEntryWidget::Page::Advanced); auto fgColor = QString("#FF0000"); auto bgColor = QString("#0000FF"); // Set foreground color @@ -513,7 +695,7 @@ void TestGui::testEditEntry() QCOMPARE(entry->historyItems().size(), ++editCount); // Test protected attributes - editEntryWidget->setCurrentPage(1); + editEntryWidget->switchToPage(EditEntryWidget::Page::Advanced); auto* attrTextEdit = editEntryWidget->findChild("attributesEdit"); QTest::mouseClick(editEntryWidget->findChild("addAttributeButton"), Qt::LeftButton); QString attrText = "TEST TEXT"; @@ -523,7 +705,7 @@ void TestGui::testEditEntry() QVERIFY(attrTextEdit->toPlainText().contains("PROTECTED")); QTest::mouseClick(editEntryWidget->findChild("revealAttributeButton"), Qt::LeftButton); QCOMPARE(attrTextEdit->toPlainText(), attrText); - editEntryWidget->setCurrentPage(0); + editEntryWidget->switchToPage(EditEntryWidget::Page::Main); // Save the edit (press OK) QTest::mouseClick(okButton, Qt::LeftButton); @@ -545,7 +727,7 @@ void TestGui::testEditEntry() QTest::mouseClick(entryEditWidget, Qt::LeftButton); okButton = editEntryWidgetButtonBox->button(QDialogButtonBox::Ok); QVERIFY(okButton); - QCOMPARE(m_dbWidget->currentMode(), DatabaseWidget::Mode::EditMode); + QCOMPARE(m_dbWidget->currentMode(), DatabaseWidget::Mode::EditEntryMode); titleEdit->setText("multiline\ntitle"); editEntryWidget->findChild("usernameComboBox")->lineEdit()->setText("multiline\nusername"); editEntryWidget->findChild("passwordEdit")->setText("multiline\npassword"); @@ -604,7 +786,7 @@ void TestGui::testSearchEditEntry() // Goto "Doggy"'s edit view QTest::keyClick(searchTextEdit, Qt::Key_Return); - QCOMPARE(m_dbWidget->currentMode(), DatabaseWidget::Mode::EditMode); + QCOMPARE(m_dbWidget->currentMode(), DatabaseWidget::Mode::EditEntryMode); // Check the path in header is "parent-group > entry" QCOMPARE(m_dbWidget->findChild("editEntryWidget")->findChild("headerLabel")->text(), @@ -630,7 +812,7 @@ void TestGui::testAddEntry() // Click the new entry button and check that we enter edit mode QTest::mouseClick(entryNewWidget, Qt::LeftButton); - QCOMPARE(m_dbWidget->currentMode(), DatabaseWidget::Mode::EditMode); + QCOMPARE(m_dbWidget->currentMode(), DatabaseWidget::Mode::EditEntryMode); // Add entry "test" and confirm added auto* editEntryWidget = m_dbWidget->findChild("editEntryWidget"); @@ -692,32 +874,23 @@ void TestGui::testPasswordEntryEntropy_data() QTest::addColumn("password"); QTest::addColumn("expectedStrengthLabel"); - QTest::newRow("Empty password") << "" - << "Password Quality: Poor"; + QTest::newRow("Empty password") << "" << "Password Quality: Poor"; - QTest::newRow("Well-known password") << "hello" - << "Password Quality: Poor"; + QTest::newRow("Well-known password") << "hello" << "Password Quality: Poor"; - QTest::newRow("Password composed of well-known words.") << "helloworld" - << "Password Quality: Poor"; + QTest::newRow("Password composed of well-known words.") << "helloworld" << "Password Quality: Poor"; - QTest::newRow("Password composed of well-known words with number.") << "password1" - << "Password Quality: Poor"; + QTest::newRow("Password composed of well-known words with number.") << "password1" << "Password Quality: Poor"; - QTest::newRow("Password out of small character space.") << "D0g.................." - << "Password Quality: Poor"; + QTest::newRow("Password out of small character space.") << "D0g.................." << "Password Quality: Poor"; - QTest::newRow("XKCD, easy substitutions.") << "Tr0ub4dour&3" - << "Password Quality: Poor"; + QTest::newRow("XKCD, easy substitutions.") << "Tr0ub4dour&3" << "Password Quality: Poor"; - QTest::newRow("XKCD, word generator.") << "correcthorsebatterystaple" - << "Password Quality: Weak"; + QTest::newRow("XKCD, word generator.") << "correcthorsebatterystaple" << "Password Quality: Weak"; - QTest::newRow("Random characters, medium length.") << "YQC3kbXbjC652dTDH" - << "Password Quality: Good"; + QTest::newRow("Random characters, medium length.") << "YQC3kbXbjC652dTDH" << "Password Quality: Good"; - QTest::newRow("Random characters, long.") << "Bs5ZFfthWzR8DGFEjaCM6bGqhmCT4km" - << "Password Quality: Excellent"; + QTest::newRow("Random characters, long.") << "Bs5ZFfthWzR8DGFEjaCM6bGqhmCT4km" << "Password Quality: Excellent"; QTest::newRow("Long password using Zxcvbn chunk estimation") << "quintet-tamper-kinswoman-humility-vengeful-haven-tastiness-aspire-widget-ipad-cussed-reaffirm-ladylike-" @@ -759,7 +932,7 @@ void TestGui::testPasswordEntryEntropy() // Click the new entry button and check that we enter edit mode QTest::mouseClick(entryNewWidget, Qt::LeftButton); - QCOMPARE(m_dbWidget->currentMode(), DatabaseWidget::Mode::EditMode); + QCOMPARE(m_dbWidget->currentMode(), DatabaseWidget::Mode::EditEntryMode); // Add entry "test" and confirm added auto* editEntryWidget = m_dbWidget->findChild("editEntryWidget"); @@ -787,6 +960,7 @@ void TestGui::testPasswordEntryEntropy() pwGeneratorWidget->findChild("editNewPassword")->findChild("passwordEdit"); auto* entropyLabel = pwGeneratorWidget->findChild("entropyLabel"); auto* strengthLabel = pwGeneratorWidget->findChild("strengthLabel"); + auto* passwordLengthLabel = pwGeneratorWidget->findChild("passwordLengthLabel"); QFETCH(QString, password); QFETCH(QString, expectedStrengthLabel); @@ -794,10 +968,12 @@ void TestGui::testPasswordEntryEntropy() // Dynamically calculate entropy due to variances with zxcvbn wordlists PasswordHealth health(password); auto expectedEntropy = QString("Entropy: %1 bit").arg(QString::number(health.entropy(), 'f', 2)); + auto expectedPasswordLength = QString("Characters: %1").arg(QString::number(password.length())); generatedPassword->setText(password); QCOMPARE(entropyLabel->text(), expectedEntropy); QCOMPARE(strengthLabel->text(), expectedStrengthLabel); + QCOMPARE(passwordLengthLabel->text(), expectedPasswordLength); QTest::mouseClick(generatedPassword, Qt::LeftButton); QTest::keyClick(generatedPassword, Qt::Key_Escape);); @@ -818,7 +994,7 @@ void TestGui::testDicewareEntryEntropy() // Click the new entry button and check that we enter edit mode QTest::mouseClick(entryNewWidget, Qt::LeftButton); - QCOMPARE(m_dbWidget->currentMode(), DatabaseWidget::Mode::EditMode); + QCOMPARE(m_dbWidget->currentMode(), DatabaseWidget::Mode::EditEntryMode); // Add entry "test" and confirm added auto* editEntryWidget = m_dbWidget->findChild("editEntryWidget"); @@ -858,11 +1034,12 @@ void TestGui::testDicewareEntryEntropy() // Verify entropy and strength auto* entropyLabel = pwGeneratorWidget->findChild("entropyLabel"); auto* strengthLabel = pwGeneratorWidget->findChild("strengthLabel"); - auto* wordLengthLabel = pwGeneratorWidget->findChild("charactersInPassphraseLabel"); + auto* wordLengthLabel = pwGeneratorWidget->findChild("passwordLengthLabel"); - QTRY_COMPARE_WITH_TIMEOUT(entropyLabel->text(), QString("Entropy: 77.55 bit"), 200); + QTRY_COMPARE_WITH_TIMEOUT(entropyLabel->text(), QString("Entropy: 77.54 bit"), 200); QCOMPARE(strengthLabel->text(), QString("Password Quality: Good")); - QCOMPARE(wordLengthLabel->text().toInt(), pwGeneratorWidget->getGeneratedPassword().size()); + QCOMPARE(wordLengthLabel->text(), + QString("Characters: %1").arg(QString::number(pwGeneratorWidget->getGeneratedPassword().length()))); QTest::mouseClick(generatedPassword, Qt::LeftButton); QTest::keyClick(generatedPassword, Qt::Key_Escape);); @@ -905,10 +1082,10 @@ void TestGui::testTotp() QVERIFY(entryEditWidget->isVisible()); QVERIFY(entryEditWidget->isEnabled()); QTest::mouseClick(entryEditWidget, Qt::LeftButton); - QCOMPARE(m_dbWidget->currentMode(), DatabaseWidget::Mode::EditMode); + QCOMPARE(m_dbWidget->currentMode(), DatabaseWidget::Mode::EditEntryMode); auto* editEntryWidget = m_dbWidget->findChild("editEntryWidget"); - editEntryWidget->setCurrentPage(1); + editEntryWidget->switchToPage(EditEntryWidget::Page::Advanced); auto* attrTextEdit = editEntryWidget->findChild("attributesEdit"); QTest::mouseClick(editEntryWidget->findChild("revealAttributeButton"), Qt::LeftButton); QCOMPARE(attrTextEdit->toPlainText(), expectedFinalSeed); @@ -922,7 +1099,7 @@ void TestGui::testTotp() auto* totpDialog = m_dbWidget->findChild("TotpDialog"); auto* totpLabel = totpDialog->findChild("totpLabel"); - QCOMPARE(totpLabel->text().replace(" ", ""), entry->totp()); + QTRY_COMPARE(totpLabel->text().replace(" ", ""), entry->totp()); QTest::keyClick(totpDialog, Qt::Key_Escape); // Test the QR code @@ -949,6 +1126,7 @@ void TestGui::testSearch() auto* searchWidget = toolBar->findChild("SearchWidget"); QVERIFY(searchWidget->isEnabled()); auto* searchTextEdit = searchWidget->findChild("searchEdit"); + auto* waitForEnterAction = searchWidget->findChild("actionSearchWaitForEnter"); auto* entryView = m_dbWidget->findChild("entryView"); QVERIFY(entryView->isVisible()); @@ -960,6 +1138,50 @@ void TestGui::testSearch() QVERIFY(helpButton->isVisible()); QVERIFY(!helpPanel->isVisible()); + // Test "wait for enter" toggle + QVERIFY(waitForEnterAction->isVisible()); + QVERIFY(waitForEnterAction->isCheckable()); + + // Test search with "wait for enter" disabled (default) + searchTextEdit->clear(); + QTest::keyClicks(searchTextEdit, "ZZZ"); + QTRY_COMPARE(searchTextEdit->text(), QString("ZZZ")); + QTRY_VERIFY(m_dbWidget->isSearchActive()); + QTRY_COMPARE(entryView->model()->rowCount(), 0); + + // Clear search + searchTextEdit->clear(); + QTRY_VERIFY(!m_dbWidget->isSearchActive()); + + // Enable "wait for enter" mode + waitForEnterAction->trigger(); + QVERIFY(waitForEnterAction->isChecked()); + + // Test search with "wait for enter" enabled + QTest::keyClicks(searchTextEdit, "ZZZ"); + QTRY_VERIFY(!m_dbWidget->isSearchActive()); + + // Press Enter to execute search + QTest::keyClick(searchTextEdit, Qt::Key_Return); + QTRY_VERIFY(m_dbWidget->isSearchActive()); + QTRY_COMPARE(entryView->model()->rowCount(), 0); + // Check that search remains active even after clearing + searchTextEdit->clear(); + QTRY_VERIFY(m_dbWidget->isSearchActive()); + + // Disable "wait for enter" mode + waitForEnterAction->trigger(); + QVERIFY(!waitForEnterAction->isChecked()); + + // Test search with "wait for enter" disabled again + QTest::keyClicks(searchTextEdit, "ZZZ"); + QTRY_VERIFY(m_dbWidget->isSearchActive()); + QTRY_COMPARE(entryView->model()->rowCount(), 0); + + // Clear search + searchTextEdit->clear(); + QTRY_VERIFY(!m_dbWidget->isSearchActive()); + // Enter search QTest::mouseClick(searchTextEdit, Qt::LeftButton); QTRY_VERIFY(searchTextEdit->hasFocus()); @@ -1021,15 +1243,15 @@ void TestGui::testSearch() searchedEntry->setPassword("password"); QClipboard* clipboard = QApplication::clipboard(); - // Attempt password copy with selected test (should fail) + // Copy to clipboard: should copy search text (not password) QTest::keyClick(searchTextEdit, Qt::Key_C, Qt::ControlModifier); - QVERIFY(clipboard->text() != searchedEntry->password()); + QCOMPARE(clipboard->text(), QString("someTHING")); // Deselect text and confirm password copies QTest::mouseClick(searchTextEdit, Qt::LeftButton); QTRY_VERIFY(searchTextEdit->selectedText().isEmpty()); QTRY_VERIFY(searchTextEdit->hasFocus()); QTest::keyClick(searchTextEdit, Qt::Key_C, Qt::ControlModifier); - QCOMPARE(searchedEntry->password(), clipboard->text()); + QCOMPARE(clipboard->text(), searchedEntry->password()); // Ensure Down focuses on entry view when search text is selected QTest::keyClick(searchTextEdit, Qt::Key_A, Qt::ControlModifier); QTest::keyClick(searchTextEdit, Qt::Key_Down); @@ -1037,14 +1259,27 @@ void TestGui::testSearch() QCOMPARE(entryView->currentEntry(), searchedEntry); // Test that password copies with entry focused QTest::keyClick(entryView, Qt::Key_C, Qt::ControlModifier); - QCOMPARE(searchedEntry->password(), clipboard->text()); + QCOMPARE(clipboard->text(), searchedEntry->password()); // Refocus back to search edit QTest::mouseClick(searchTextEdit, Qt::LeftButton); QTRY_VERIFY(searchTextEdit->hasFocus()); - // Test that password does not copy + // Select search text and test that password does not copy searchTextEdit->selectAll(); QTest::keyClick(searchTextEdit, Qt::Key_C, Qt::ControlModifier); QTRY_COMPARE(clipboard->text(), QString("someTHING")); + // Ensure password copies when clicking on copy password button despite selected text + auto copyPasswordAction = m_mainWindow->findChild("actionEntryCopyPassword"); + QVERIFY(copyPasswordAction); + auto copyPasswordWidget = toolBar->widgetForAction(copyPasswordAction); + QVERIFY(copyPasswordWidget); + QTest::mouseClick(copyPasswordWidget, Qt::LeftButton); + QCOMPARE(clipboard->text(), searchedEntry->password()); + // Deselect text and deselect entry, Ctrl+C should now do nothing + clipboard->clear(); + QTest::mouseClick(searchTextEdit, Qt::LeftButton); + entryView->clearSelection(); + QTest::keyClick(searchTextEdit, Qt::Key_C, Qt::ControlModifier); + QCOMPARE(clipboard->text(), QString()); // Test case sensitive search searchWidget->setCaseSensitive(true); @@ -1096,7 +1331,7 @@ void TestGui::testSearch() QModelIndex item = entryView->model()->index(0, 1); Entry* entry = entryView->entryFromIndex(item); QTest::keyClick(searchTextEdit, Qt::Key_Return); - QCOMPARE(m_dbWidget->currentMode(), DatabaseWidget::Mode::EditMode); + QCOMPARE(m_dbWidget->currentMode(), DatabaseWidget::Mode::EditEntryMode); // Perform the edit and save it EditEntryWidget* editEntryWidget = m_dbWidget->findChild("editEntryWidget"); @@ -1254,7 +1489,7 @@ void TestGui::testEntryPlaceholders() // Click the new entry button and check that we enter edit mode QTest::mouseClick(entryNewWidget, Qt::LeftButton); - QCOMPARE(m_dbWidget->currentMode(), DatabaseWidget::Mode::EditMode); + QCOMPARE(m_dbWidget->currentMode(), DatabaseWidget::Mode::EditEntryMode); // Add entry "test" and confirm added auto* editEntryWidget = m_dbWidget->findChild("editEntryWidget"); @@ -1419,18 +1654,14 @@ void TestGui::testSaveBackupPath_data() QTest::newRow("Absolute backup path") << tmpFile.fileName() << tmpFile.fileName(); // relative paths should be resolved to database parent directory - QTest::newRow("Relative backup path (implicit)") << "other_dir/test.old.kdbx" - << "other_dir/test.old.kdbx"; - QTest::newRow("Relative backup path (explicit)") << "./other_dir2/test2.old.kdbx" - << "other_dir2/test2.old.kdbx"; + QTest::newRow("Relative backup path (implicit)") << "other_dir/test.old.kdbx" << "other_dir/test.old.kdbx"; + QTest::newRow("Relative backup path (explicit)") << "./other_dir2/test2.old.kdbx" << "other_dir2/test2.old.kdbx"; - QTest::newRow("Path with placeholders") << "{DB_FILENAME}.old.kdbx" - << "KeePassXC.old.kdbx"; + QTest::newRow("Path with placeholders") << "{DB_FILENAME}.old.kdbx" << "KeePassXC.old.kdbx"; // empty path should be replaced with default pattern QTest::newRow("Empty path") << QString("") << config()->getDefault(Config::BackupFilePathPattern).toString(); // {DB_FILENAME} should be replaced with database filename - QTest::newRow("") << "{DB_FILENAME}_.old.kdbx" - << "{DB_FILENAME}_.old.kdbx"; + QTest::newRow("") << "{DB_FILENAME}_.old.kdbx" << "{DB_FILENAME}_.old.kdbx"; } void TestGui::testSaveBackupPath() @@ -1482,24 +1713,82 @@ void TestGui::testDatabaseSettings() int autosaveDelayTestValue = 2; dbSettingsCategoryList->setCurrentCategory(1); // go into security category - dbSettingsStackedWidget->findChild()->setCurrentIndex(1); // go into encryption tab + auto securityTabWidget = dbSettingsStackedWidget->findChild("securityTabWidget"); + QCOMPARE(securityTabWidget->currentIndex(), 0); - auto encryptionSettings = dbSettingsDialog->findChild("encryptionSettingsTabWidget"); + // Interact with the password edit option + auto passwordEditWidget = securityTabWidget->findChild(); + QVERIFY(passwordEditWidget); + auto editPasswordButton = passwordEditWidget->findChild("changeButton"); + QVERIFY(editPasswordButton); + QVERIFY(editPasswordButton->isVisible()); + QTest::mouseClick(editPasswordButton, Qt::LeftButton); + QApplication::processEvents(); + auto passwordWidgets = dbSettingsDialog->findChildren(); + QVERIFY(passwordWidgets.count() == 2); + QVERIFY(passwordWidgets[0]->isVisible()); + passwordWidgets[0]->setText("b"); + passwordWidgets[1]->setText("b"); + + // Toggle between tabs to ensure the password remains + securityTabWidget->setCurrentIndex(1); + QApplication::processEvents(); + securityTabWidget->setCurrentIndex(0); + QApplication::processEvents(); + QCOMPARE(passwordWidgets[0]->text(), QString("b")); + + // Cancel password change and confirm password is cleared + auto cancelPasswordButton = passwordEditWidget->findChild("cancelButton"); + QVERIFY(cancelPasswordButton); + QTest::mouseClick(cancelPasswordButton, Qt::LeftButton); + QApplication::processEvents(); + QVERIFY(!passwordWidgets[0]->isVisible()); + QCOMPARE(passwordWidgets[0]->text(), QString("")); + QVERIFY(editPasswordButton->isVisible()); + + // Switch to encryption tab and interact with various settings + securityTabWidget->setCurrentIndex(1); + QApplication::processEvents(); + + // Verify database is KDBX3 + auto compatibilitySelection = securityTabWidget->findChild("compatibilitySelection"); + QVERIFY(compatibilitySelection); + QVERIFY(compatibilitySelection->isEnabled()); + QCOMPARE(compatibilitySelection->currentText(), QString("KDBX 3")); + + // Verify advanced settings + auto encryptionSettings = securityTabWidget->findChild("encryptionSettingsTabWidget"); auto advancedTab = encryptionSettings->findChild("advancedTab"); encryptionSettings->setCurrentWidget(advancedTab); - QApplication::processEvents(); + // Verify KDF is AES KDBX3 + auto kdfSelection = advancedTab->findChild("kdfComboBox"); + QVERIFY(kdfSelection->isVisible()); + QCOMPARE(kdfSelection->currentText(), QString("AES-KDF (KDBX 3)")); + auto transformRoundsSpinBox = advancedTab->findChild("transformRoundsSpinBox"); QVERIFY(transformRoundsSpinBox); - QVERIFY(transformRoundsSpinBox->isVisible()); + // Adjust compatibility to KDBX4 and wait for KDF to update + compatibilitySelection->setCurrentIndex(0); + QTRY_VERIFY(transformRoundsSpinBox->isEnabled()); + QCOMPARE(compatibilitySelection->currentText().left(6), QString("KDBX 4")); + QCOMPARE(kdfSelection->currentText().left(7), QString("Argon2d")); + + // Switch to AES KDBX4, change rounds, then accept + kdfSelection->setCurrentIndex(2); + QCOMPARE(kdfSelection->currentText(), QString("AES-KDF (KDBX 4)")); transformRoundsSpinBox->setValue(123456); QTest::keyClick(transformRoundsSpinBox, Qt::Key_Enter); QTRY_COMPARE(m_db->kdf()->rounds(), 123456); + QVERIFY(m_db->formatVersion() >= KeePass2::FILE_VERSION_4); + QCOMPARE(m_db->kdf()->uuid(), KeePass2::KDF_AES_KDBX4); + + // Go back into database settings + triggerAction("actionDatabaseSettings"); // test disable and default values for maximum history items and size - triggerAction("actionDatabaseSettings"); auto* historyMaxItemsCheckBox = dbSettingsDialog->findChild("historyMaxItemsCheckBox"); auto* historyMaxItemsSpinBox = dbSettingsDialog->findChild("historyMaxItemsSpinBox"); auto* historyMaxSizeCheckBox = dbSettingsDialog->findChild("historyMaxSizeCheckBox"); @@ -1553,7 +1842,7 @@ void TestGui::testDatabaseSettings() QWidget* entryNewWidget = toolBar->widgetForAction(entryNewAction); QTest::mouseClick(entryNewWidget, Qt::LeftButton); - QCOMPARE(m_dbWidget->currentMode(), DatabaseWidget::Mode::EditMode); + QCOMPARE(m_dbWidget->currentMode(), DatabaseWidget::Mode::EditEntryMode); auto* editEntryWidget = m_dbWidget->findChild("editEntryWidget"); QVERIFY(editEntryWidget); @@ -1563,7 +1852,7 @@ void TestGui::testDatabaseSettings() QTest::keyClicks(titleEdit, "Test autosaveDelay 1"); // 2.b) Save changes - editEntryWidget->setCurrentPage(0); + editEntryWidget->switchToPage(EditEntryWidget::Page::Main); auto* editEntryWidgetButtonBox = editEntryWidget->findChild("buttonBox"); QTest::mouseClick(editEntryWidgetButtonBox->button(QDialogButtonBox::Ok), Qt::LeftButton); @@ -1573,11 +1862,11 @@ void TestGui::testDatabaseSettings() // 2.d) Create second entry to test delay timer reset QTest::mouseClick(entryNewWidget, Qt::LeftButton); - QCOMPARE(m_dbWidget->currentMode(), DatabaseWidget::Mode::EditMode); + QCOMPARE(m_dbWidget->currentMode(), DatabaseWidget::Mode::EditEntryMode); QTest::keyClicks(titleEdit, "Test autosaveDelay 2"); // 2.e) Save changes - editEntryWidget->setCurrentPage(0); + editEntryWidget->switchToPage(EditEntryWidget::Page::Main); editEntryWidgetButtonBox = editEntryWidget->findChild("buttonBox"); QTest::mouseClick(editEntryWidgetButtonBox->button(QDialogButtonBox::Ok), Qt::LeftButton); @@ -1593,11 +1882,11 @@ void TestGui::testDatabaseSettings() // 4 Test no delay when disabled autosave or autosaveDelay // 4.a) create new entry QTest::mouseClick(entryNewWidget, Qt::LeftButton); - QCOMPARE(m_dbWidget->currentMode(), DatabaseWidget::Mode::EditMode); + QCOMPARE(m_dbWidget->currentMode(), DatabaseWidget::Mode::EditEntryMode); QTest::keyClicks(titleEdit, "Test autosaveDelay 3"); // 4.b) Save changes - editEntryWidget->setCurrentPage(0); + editEntryWidget->switchToPage(EditEntryWidget::Page::Main); editEntryWidgetButtonBox = editEntryWidget->findChild("buttonBox"); QTest::mouseClick(editEntryWidgetButtonBox->button(QDialogButtonBox::Ok), Qt::LeftButton); @@ -1614,9 +1903,9 @@ void TestGui::testDatabaseSettings() // 4.f) Repeat for autosaveDelay config()->set(Config::AutoSaveAfterEveryChange, true); QTest::mouseClick(entryNewWidget, Qt::LeftButton); - QCOMPARE(m_dbWidget->currentMode(), DatabaseWidget::Mode::EditMode); + QCOMPARE(m_dbWidget->currentMode(), DatabaseWidget::Mode::EditEntryMode); QTest::keyClicks(titleEdit, "Test autosaveDelay 4"); - editEntryWidget->setCurrentPage(0); + editEntryWidget->switchToPage(EditEntryWidget::Page::Main); editEntryWidgetButtonBox = editEntryWidget->findChild("buttonBox"); QTest::mouseClick(editEntryWidgetButtonBox->button(QDialogButtonBox::Ok), Qt::LeftButton); Tools::wait(150); // due to modify timer @@ -1823,6 +2112,52 @@ void TestGui::testTrayRestoreHide() #endif } +void TestGui::testShortcutConfig() +{ + // Action collection should not be empty + QVERIFY(!ActionCollection::instance()->actions().isEmpty()); + + // Add an action, make sure it gets added + QAction* a = new QAction(ActionCollection::instance()); + a->setObjectName("MyAction1"); + ActionCollection::instance()->addAction(a); + QVERIFY(ActionCollection::instance()->actions().contains(a)); + + const QKeySequence seq(Qt::CTRL + Qt::SHIFT + Qt::ALT + Qt::Key_N); + ActionCollection::instance()->setDefaultShortcut(a, seq); + QCOMPARE(ActionCollection::instance()->defaultShortcut(a), seq); + + bool v = false; + m_mainWindow->addAction(a); + connect(a, &QAction::triggered, ActionCollection::instance(), [&v] { v = !v; }); + QTest::keyClick(m_mainWindow.data(), Qt::Key_N, Qt::ControlModifier | Qt::ShiftModifier | Qt::AltModifier); + QVERIFY(v); + + // Change shortcut and save + const QKeySequence newSeq(Qt::CTRL + Qt::SHIFT + Qt::ALT + Qt::Key_M); + a->setShortcut(newSeq); + QVERIFY(a->shortcut() != ActionCollection::instance()->defaultShortcut(a)); + ActionCollection::instance()->saveShortcuts(); + QCOMPARE(a->shortcut(), newSeq); + const auto shortcuts = Config::instance()->getShortcuts(); + Config::ShortcutEntry entryForA; + for (const auto& s : shortcuts) { + if (s.name == a->objectName()) { + entryForA = s; + break; + } + } + QCOMPARE(entryForA.name, a->objectName()); + QCOMPARE(QKeySequence::fromString(entryForA.shortcut), a->shortcut()); + + // trigger the old shortcut + QTest::keyClick(m_mainWindow.data(), Qt::Key_N, Qt::ControlModifier | Qt::ShiftModifier | Qt::AltModifier); + QVERIFY(v); // value of v should not change + QTest::keyClick(m_mainWindow.data(), Qt::Key_M, Qt::ControlModifier | Qt::ShiftModifier | Qt::AltModifier); + QVERIFY(!v); + disconnect(a, nullptr, nullptr, nullptr); +} + void TestGui::testAutoType() { // Clear entries from root group to guarantee order @@ -1845,7 +2180,7 @@ void TestGui::testAutoType() QVERIFY(entryNewWidget->isEnabled()); QTest::mouseClick(entryNewWidget, Qt::LeftButton); - QCOMPARE(m_dbWidget->currentMode(), DatabaseWidget::Mode::EditMode); + QCOMPARE(m_dbWidget->currentMode(), DatabaseWidget::Mode::EditEntryMode); auto* editEntryWidget = m_dbWidget->findChild("editEntryWidget"); QVERIFY(editEntryWidget); @@ -1862,7 +2197,7 @@ void TestGui::testAutoType() QTest::keyClicks(usernameComboBox, "AutocompletionUsername"); // 1.b) Uncheck Auto-Type checkbox - editEntryWidget->setCurrentPage(3); + editEntryWidget->switchToPage(EditEntryWidget::Page::AutoType); auto* enableAutoTypeButton = editEntryWidget->findChild("enableButton"); QVERIFY(enableAutoTypeButton); QVERIFY(enableAutoTypeButton->isVisible()); @@ -1872,7 +2207,7 @@ void TestGui::testAutoType() QVERIFY(!enableAutoTypeButton->isChecked()); // 1.c) Save changes - editEntryWidget->setCurrentPage(0); + editEntryWidget->switchToPage(EditEntryWidget::Page::Main); auto* editEntryWidgetButtonBox = editEntryWidget->findChild("buttonBox"); QTest::mouseClick(editEntryWidgetButtonBox->button(QDialogButtonBox::Ok), Qt::LeftButton); @@ -1880,32 +2215,32 @@ void TestGui::testAutoType() // 2.a) Click the new entry button and set the title QTest::mouseClick(entryNewWidget, Qt::LeftButton); - QCOMPARE(m_dbWidget->currentMode(), DatabaseWidget::Mode::EditMode); + QCOMPARE(m_dbWidget->currentMode(), DatabaseWidget::Mode::EditEntryMode); QTest::keyClicks(titleEdit, "2. Entry With Default Auto-Type Sequence"); QTest::mouseClick(usernameComboBox, Qt::LeftButton); QTest::keyClicks(usernameComboBox, "AutocompletionUsername"); // 2.b) Confirm AutoType is enabled and default - editEntryWidget->setCurrentPage(3); + editEntryWidget->switchToPage(EditEntryWidget::Page::AutoType); QVERIFY(enableAutoTypeButton->isChecked()); auto* inheritSequenceButton = editEntryWidget->findChild("inheritSequenceButton"); QVERIFY(inheritSequenceButton->isChecked()); // 2.c) Save changes - editEntryWidget->setCurrentPage(0); + editEntryWidget->switchToPage(EditEntryWidget::Page::Main); QTest::mouseClick(editEntryWidgetButtonBox->button(QDialogButtonBox::Ok), Qt::LeftButton); // 3. Create an entry with custom Auto-Type sequence // 3.a) Click the new entry button and set the title QTest::mouseClick(entryNewWidget, Qt::LeftButton); - QCOMPARE(m_dbWidget->currentMode(), DatabaseWidget::Mode::EditMode); + QCOMPARE(m_dbWidget->currentMode(), DatabaseWidget::Mode::EditEntryMode); QTest::keyClicks(titleEdit, "3. Entry With Custom Auto-Type Sequence"); QTest::mouseClick(usernameComboBox, Qt::LeftButton); QTest::keyClicks(usernameComboBox, "AutocompletionUsername"); // 3.b) Confirm AutoType is enabled and set custom sequence - editEntryWidget->setCurrentPage(3); + editEntryWidget->switchToPage(EditEntryWidget::Page::AutoType); QVERIFY(enableAutoTypeButton->isChecked()); auto* customSequenceButton = editEntryWidget->findChild("customSequenceButton"); QTest::mouseClick(customSequenceButton, Qt::LeftButton); @@ -1918,7 +2253,7 @@ void TestGui::testAutoType() QTest::keyClicks(sequenceEdit, "{USERNAME}{TAB}{TAB}{PASSWORD}{ENTER}"); // 3.c) Save changes - editEntryWidget->setCurrentPage(0); + editEntryWidget->switchToPage(EditEntryWidget::Page::Main); QTest::mouseClick(editEntryWidgetButtonBox->button(QDialogButtonBox::Ok), Qt::LeftButton); QApplication::processEvents(); @@ -1976,6 +2311,155 @@ void TestGui::testAutoType() entryView->selectionModel()->clearSelection(); } +void TestGui::testMenuActionStates() +{ + auto isActionEnabled = [this](const QString& actionName) -> bool { + auto action = m_mainWindow->findChild(actionName); + if (!action) { + QTest::qFail(qPrintable(QString("Invalid action specified: %1").arg(actionName)), __FILE__, __LINE__); + return false; + } + return action->isEnabled(); + }; + + // Start with database open and unlocked + qInfo("Actions Test: Database open and unlocked"); + + QVERIFY(isActionEnabled("actionEntryNew")); + QVERIFY(isActionEnabled("actionGroupNew")); + QVERIFY(isActionEnabled("actionDatabaseSaveAs")); + QVERIFY(isActionEnabled("actionDatabaseClose")); + QVERIFY(isActionEnabled("actionDatabaseMerge")); + QVERIFY(isActionEnabled("actionDatabaseSettings")); + QVERIFY(isActionEnabled("actionReports")); + QVERIFY(isActionEnabled("actionLockDatabase")); + QVERIFY(isActionEnabled("actionLockAllDatabases")); + QVERIFY(isActionEnabled("actionImport")); + QVERIFY(isActionEnabled("actionExportCsv")); + QVERIFY(isActionEnabled("actionSettings")); + QVERIFY(isActionEnabled("actionPasswordGenerator")); + + // Edit entry actions + qInfo("Actions Test: Editing an entry"); + + triggerAction("actionEntryEdit"); + + QVERIFY(!isActionEnabled("actionEntryNew")); + QVERIFY(isActionEnabled("actionEntryCopyUsername")); + QVERIFY(!isActionEnabled("actionEntrySetupTotp")); + QVERIFY(!isActionEnabled("actionGroupNew")); + QVERIFY(isActionEnabled("actionDatabaseSaveAs")); + QVERIFY(isActionEnabled("actionDatabaseClose")); + QVERIFY(!isActionEnabled("actionDatabaseMerge")); + QVERIFY(!isActionEnabled("actionDatabaseSettings")); + QVERIFY(!isActionEnabled("actionReports")); + QVERIFY(isActionEnabled("actionLockDatabase")); + QVERIFY(isActionEnabled("actionLockAllDatabases")); + QVERIFY(isActionEnabled("actionSettings")); + QVERIFY(isActionEnabled("actionPasswordGenerator")); + + // Special Case - Recycle Bin + qInfo("Actions Test: Special case - Recycle Bin"); + + m_dbWidget->switchToMainView(); + QApplication::processEvents(); + + QVERIFY(m_db->metadata()->recycleBinEnabled()); + triggerAction("actionEntryDelete"); + m_dbWidget->groupView()->setCurrentGroup(m_db->metadata()->recycleBin()); + QVERIFY(m_dbWidget->isRecycleBinSelected()); + QVERIFY(isActionEnabled("actionEntryRestore")); + QVERIFY(isActionEnabled("actionGroupEmptyRecycleBin")); + QVERIFY(!isActionEnabled("actionEntryNew")); + QVERIFY(!isActionEnabled("actionEntryClone")); + QVERIFY(!isActionEnabled("actionGroupNew")); + QVERIFY(!isActionEnabled("actionGroupClone")); + + // Database Settings + qInfo("Actions Test: Database settings"); + triggerAction("actionDatabaseSettings"); + + QVERIFY(!isActionEnabled("actionEntryNew")); + QVERIFY(!isActionEnabled("actionEntrySetupTotp")); + QVERIFY(!isActionEnabled("actionGroupNew")); + QVERIFY(isActionEnabled("actionDatabaseSaveAs")); + QVERIFY(isActionEnabled("actionDatabaseClose")); + QVERIFY(!isActionEnabled("actionDatabaseMerge")); + QVERIFY(isActionEnabled("actionDatabaseSettings")); + QVERIFY(isActionEnabled("actionDatabaseSecurity")); + QVERIFY(!isActionEnabled("actionReports")); + QVERIFY(isActionEnabled("actionLockDatabase")); + QVERIFY(isActionEnabled("actionSettings")); + QVERIFY(isActionEnabled("actionPasswordGenerator")); + + // Database Reports + qInfo("Actions Test: Database reports"); + + triggerAction("actionDatabaseSettings"); + triggerAction("actionReports"); + + QVERIFY(!isActionEnabled("actionEntryNew")); + QVERIFY(!isActionEnabled("actionEntrySetupTotp")); + QVERIFY(!isActionEnabled("actionGroupNew")); + QVERIFY(isActionEnabled("actionDatabaseSaveAs")); + QVERIFY(isActionEnabled("actionDatabaseClose")); + QVERIFY(!isActionEnabled("actionDatabaseMerge")); + QVERIFY(!isActionEnabled("actionDatabaseSettings")); + QVERIFY(!isActionEnabled("actionDatabaseSecurity")); + QVERIFY(isActionEnabled("actionReports")); + QVERIFY(isActionEnabled("actionLockDatabase")); + QVERIFY(isActionEnabled("actionSettings")); + QVERIFY(isActionEnabled("actionPasswordGenerator")); + + // Application Settings + qInfo("Actions Test: Application settings"); + + triggerAction("actionSettings"); + + QVERIFY(!isActionEnabled("actionDatabaseSettings")); + QVERIFY(!isActionEnabled("actionDatabaseSecurity")); + QVERIFY(!isActionEnabled("actionReports")); + QVERIFY(isActionEnabled("actionSettings")); + QVERIFY(isActionEnabled("actionPasswordGenerator")); + + // Locked Database + qInfo("Actions Test: Database locked"); + + triggerAction("actionSettings"); + MessageBox::setNextAnswer(MessageBox::Discard); + triggerAction("actionLockDatabase"); + + QVERIFY(!isActionEnabled("actionEntryNew")); + QVERIFY(!isActionEnabled("actionGroupNew")); + QVERIFY(!isActionEnabled("actionDatabaseSaveAs")); + QVERIFY(isActionEnabled("actionDatabaseClose")); + QVERIFY(!isActionEnabled("actionDatabaseMerge")); + QVERIFY(!isActionEnabled("actionDatabaseSettings")); + QVERIFY(!isActionEnabled("actionReports")); + QVERIFY(!isActionEnabled("actionLockDatabase")); + QVERIFY(!isActionEnabled("actionLockAllDatabases")); + QVERIFY(isActionEnabled("actionSettings")); + QVERIFY(isActionEnabled("actionPasswordGenerator")); + + // Welcome Screen + qInfo("Actions Test: Welcome screen"); + + triggerAction("actionDatabaseClose"); + + QVERIFY(!isActionEnabled("actionEntryNew")); + QVERIFY(!isActionEnabled("actionGroupNew")); + QVERIFY(!isActionEnabled("actionDatabaseSaveAs")); + QVERIFY(!isActionEnabled("actionDatabaseClose")); + QVERIFY(!isActionEnabled("actionDatabaseMerge")); + QVERIFY(!isActionEnabled("actionDatabaseSettings")); + QVERIFY(!isActionEnabled("actionReports")); + QVERIFY(!isActionEnabled("actionLockDatabase")); + QVERIFY(!isActionEnabled("actionLockAllDatabases")); + QVERIFY(isActionEnabled("actionImport")); + QVERIFY(isActionEnabled("actionSettings")); + QVERIFY(isActionEnabled("actionPasswordGenerator")); +} + void TestGui::addCannedEntries() { // Find buttons @@ -2050,8 +2534,8 @@ void TestGui::checkStatusBarText(const QString& textFragment) void TestGui::triggerAction(const QString& name) { auto* action = m_mainWindow->findChild(name); - QVERIFY(action); - QVERIFY(action->isEnabled()); + QVERIFY2(action, qPrintable(QString("Action doesn't exist: %1").arg(name))); + QVERIFY2(action->isEnabled(), qPrintable(QString("Action is disabled: %1").arg(name))); action->trigger(); QApplication::processEvents(); } diff --git a/tests/gui/TestGui.h b/tests/gui/TestGui.h index fa3d613f9..514f7ce95 100644 --- a/tests/gui/TestGui.h +++ b/tests/gui/TestGui.h @@ -40,6 +40,9 @@ private slots: void testSettingsDefaultTabOrder(); void testCreateDatabase(); void testMergeDatabase(); + void testRemoteSyncDatabaseSameKey(); + void testRemoteSyncDatabaseRequiresPassword(); + void testOpenRemoteDatabase(); void testAutoreloadDatabase(); void testTabs(); void testEditEntry(); @@ -66,6 +69,8 @@ private slots: void testSortGroups(); void testAutoType(); void testTrayRestoreHide(); + void testShortcutConfig(); + void testMenuActionStates(); private: void addCannedEntries(); @@ -81,9 +86,10 @@ private: void clickIndex(const QModelIndex& index, QAbstractItemView* view, Qt::MouseButton button, - Qt::KeyboardModifiers stateKey = 0); + Qt::KeyboardModifiers stateKey = {}); void checkSaveDatabase(); void checkStatusBarText(const QString& textFragment); + void prepareAndTriggerRemoteSync(); QScopedPointer m_mainWindow; QPointer m_statusBarLabel; diff --git a/tests/gui/TestGuiBrowser.cpp b/tests/gui/TestGuiBrowser.cpp index 68698b5fb..26fd72690 100644 --- a/tests/gui/TestGuiBrowser.cpp +++ b/tests/gui/TestGuiBrowser.cpp @@ -41,10 +41,8 @@ int main(int argc, char* argv[]) { -#if QT_VERSION >= QT_VERSION_CHECK(5, 6, 0) QApplication::setAttribute(Qt::AA_EnableHighDpiScaling); QGuiApplication::setAttribute(Qt::AA_UseHighDpiPixmaps); -#endif Application app(argc, argv); app.setApplicationName("KeePassXC"); app.setApplicationVersion(KEEPASSXC_VERSION); @@ -60,7 +58,8 @@ int main(int argc, char* argv[]) void TestGuiBrowser::initTestCase() { QVERIFY(Crypto::init()); - Config::createTempFileInstance(); + // Create temporary config file + Config::createConfigFromFile(TemporaryFile::createTempConfigFile(), {}); // Disable autosave so we can test the modified file indicator config()->set(Config::AutoSaveAfterEveryChange, false); config()->set(Config::AutoSaveOnExit, false); @@ -144,7 +143,7 @@ void TestGuiBrowser::testEntrySettings() auto* entryEditAction = m_mainWindow->findChild("actionEntryEdit"); QWidget* entryEditWidget = toolBar->widgetForAction(entryEditAction); QTest::mouseClick(entryEditWidget, Qt::LeftButton); - QCOMPARE(m_dbWidget->currentMode(), DatabaseWidget::Mode::EditMode); + QCOMPARE(m_dbWidget->currentMode(), DatabaseWidget::Mode::EditEntryMode); auto* editEntryWidget = m_dbWidget->findChild("editEntryWidget"); // Switch to Properties page and select all rows from the custom data table @@ -188,7 +187,7 @@ void TestGuiBrowser::testAdditionalURLs() auto* entryEditAction = m_mainWindow->findChild("actionEntryEdit"); QWidget* entryEditWidget = toolBar->widgetForAction(entryEditAction); QTest::mouseClick(entryEditWidget, Qt::LeftButton); - QCOMPARE(m_dbWidget->currentMode(), DatabaseWidget::Mode::EditMode); + QCOMPARE(m_dbWidget->currentMode(), DatabaseWidget::Mode::EditEntryMode); auto* editEntryWidget = m_dbWidget->findChild("editEntryWidget"); // Switch to Browser Integration page and add three URL's diff --git a/tests/gui/TestGuiBrowser.h b/tests/gui/TestGuiBrowser.h index d34a97f01..4d88a3a75 100644 --- a/tests/gui/TestGuiBrowser.h +++ b/tests/gui/TestGuiBrowser.h @@ -46,7 +46,7 @@ private: void clickIndex(const QModelIndex& index, QAbstractItemView* view, Qt::MouseButton button, - Qt::KeyboardModifiers stateKey = 0); + Qt::KeyboardModifiers stateKey = {}); QScopedPointer m_mainWindow; QPointer m_tabWidget; diff --git a/tests/gui/TestGuiFdoSecrets.cpp b/tests/gui/TestGuiFdoSecrets.cpp index 8de34e71a..fc7e218ea 100644 --- a/tests/gui/TestGuiFdoSecrets.cpp +++ b/tests/gui/TestGuiFdoSecrets.cpp @@ -26,6 +26,7 @@ #include "config-keepassx-tests.h" +#include "core/Global.h" #include "core/Tools.h" #include "crypto/Crypto.h" #include "gui/Application.h" @@ -46,10 +47,8 @@ int main(int argc, char* argv[]) { -#if QT_VERSION >= QT_VERSION_CHECK(5, 6, 0) QApplication::setAttribute(Qt::AA_EnableHighDpiScaling); QGuiApplication::setAttribute(Qt::AA_UseHighDpiPixmaps); -#endif Application app(argc, argv); app.setApplicationName("KeePassXC"); app.setApplicationVersion(KEEPASSXC_VERSION); @@ -120,8 +119,8 @@ class FakeClient : public DBusClient public: explicit FakeClient(DBusMgr* dbus) : DBusClient( - dbus, - {QStringLiteral("local"), 0, true, {ProcInfo{0, 0, QStringLiteral("fake-client"), QString{}, QString{}}}}) + dbus, + {QStringLiteral("local"), 0, true, {ProcInfo{0, 0, QStringLiteral("fake-client"), QString{}, QString{}}}}) { } }; @@ -137,7 +136,8 @@ TestGuiFdoSecrets::~TestGuiFdoSecrets() = default; void TestGuiFdoSecrets::initTestCase() { VERIFY(Crypto::init()); - Config::createTempFileInstance(); + // Create temporary config file + Config::createConfigFromFile(TemporaryFile::createTempConfigFile(), {}); config()->set(Config::AutoSaveAfterEveryChange, false); config()->set(Config::AutoSaveOnExit, false); config()->set(Config::GUI_ShowTrayIcon, true); @@ -420,7 +420,7 @@ void TestGuiFdoSecrets::testServiceSearchBlockingUnlockMultiple() VERIFY(service); // when there are multiple locked databases, - // repeatly show the dialog until there is at least one unlocked collection + // repeatedly show the dialog until there is at least one unlocked collection FdoSecrets::settings()->setUnlockBeforeSearch(true); // when only unlocking the one with no exposed group, a second dialog is shown @@ -1248,7 +1248,7 @@ void TestGuiFdoSecrets::testItemReplace() { DBUS_GET2(unlocked, locked, service->SearchItems({{"application", "fdosecrets-test"}})); QSet expected{QDBusObjectPath(item1->path()), QDBusObjectPath(item2->path())}; - COMPARE(QSet::fromList(unlocked), expected); + COMPARE(Tools::asSet(unlocked), expected); } QSignalSpy spyItemCreated(coll.data(), SIGNAL(ItemCreated(QDBusObjectPath))); @@ -1265,7 +1265,7 @@ void TestGuiFdoSecrets::testItemReplace() // there are still 2 entries DBUS_GET2(unlocked, locked, service->SearchItems({{"application", "fdosecrets-test"}})); QSet expected{QDBusObjectPath(item1->path()), QDBusObjectPath(item2->path())}; - COMPARE(QSet::fromList(unlocked), expected); + COMPARE(Tools::asSet(unlocked), expected); VERIFY(waitForSignal(spyItemCreated, 0)); // there may be multiple changed signals, due to each item attribute is set separately @@ -1291,7 +1291,7 @@ void TestGuiFdoSecrets::testItemReplace() QDBusObjectPath(item2->path()), QDBusObjectPath(item4->path()), }; - COMPARE(QSet::fromList(unlocked), expected); + COMPARE(Tools::asSet(unlocked), expected); VERIFY(waitForSignal(spyItemCreated, 1)); { @@ -1619,7 +1619,7 @@ void TestGuiFdoSecrets::testExposeSubgroup() for (const auto& itemPath : itemPaths) { exposedEntries << m_plugin->dbus()->pathToObject(itemPath)->backend(); } - COMPARE(exposedEntries, QSet::fromList(subgroup->entries())); + COMPARE(exposedEntries, Tools::asSet(subgroup->entries())); } void TestGuiFdoSecrets::testModifyingExposedGroup() diff --git a/tests/gui/attachments/TestAttachmentWidget.cpp b/tests/gui/attachments/TestAttachmentWidget.cpp new file mode 100644 index 000000000..a0d17fcac --- /dev/null +++ b/tests/gui/attachments/TestAttachmentWidget.cpp @@ -0,0 +1,94 @@ +#include "TestAttachmentWidget.h" + +#include + +#include +#include +#include + +#include +#include +#include + +void TestAttachmentsWidget::initTestCase() +{ + m_attachmentWidget.reset(new AttachmentWidget()); + + QVERIFY(m_attachmentWidget); +} + +void TestAttachmentsWidget::testTextAttachment() +{ + for (const auto& attachment : {attachments::Attachment{.name = "Test.txt", .data = "Test"}, + attachments::Attachment{.name = "Test.html", .data = "

    test

    "}, + attachments::Attachment{.name = "Test.md", .data = "**bold**"}}) { + for (auto mode : {attachments::OpenMode::ReadWrite, attachments::OpenMode::ReadOnly}) { + m_attachmentWidget->openAttachment(attachment, mode); + + QCoreApplication::processEvents(); + + auto layout = m_attachmentWidget->findChild("verticalLayout"); + QVERIFY(layout); + + QCOMPARE(layout->count(), 1); + + auto item = layout->itemAt(0); + QVERIFY(item); + + QVERIFY(qobject_cast(item->widget())); + + auto actualAttachment = m_attachmentWidget->getAttachment(); + QCOMPARE(actualAttachment.name, attachment.name); + QCOMPARE(actualAttachment.data, attachment.data); + } + } +} + +void TestAttachmentsWidget::testImageAttachment() +{ + const auto Attachment = attachments::Attachment{.name = "Test.jpg", .data = QByteArray::fromHex("FFD8FF")}; + + m_attachmentWidget->openAttachment(Attachment, attachments::OpenMode::ReadWrite); + + QCoreApplication::processEvents(); + + auto layout = m_attachmentWidget->findChild("verticalLayout"); + QVERIFY(layout); + + QCOMPARE(layout->count(), 1); + + auto item = layout->itemAt(0); + QVERIFY(item); + + QVERIFY(qobject_cast(item->widget())); + + auto actualAttachment = m_attachmentWidget->getAttachment(); + QCOMPARE(actualAttachment.name, Attachment.name); + QCOMPARE(actualAttachment.data, Attachment.data); +} + +void TestAttachmentsWidget::testUnknownAttachment() +{ + const auto Attachment = attachments::Attachment{.name = "Test", .data = QByteArray{"ID3"}}; + + m_attachmentWidget->openAttachment(Attachment, attachments::OpenMode::ReadWrite); + + QCoreApplication::processEvents(); + + auto layout = m_attachmentWidget->findChild("verticalLayout"); + QVERIFY(layout); + + QCOMPARE(layout->count(), 1); + + auto item = layout->itemAt(0); + QVERIFY(item); + + auto label = qobject_cast(item->widget()); + QVERIFY(label); + + QVERIFY(!label->text().isEmpty()); + + auto actualAttachment = m_attachmentWidget->getAttachment(); + QCOMPARE(actualAttachment.name, Attachment.name); + QCOMPARE(actualAttachment.data, Attachment.data); +} diff --git a/tests/gui/attachments/TestAttachmentWidget.h b/tests/gui/attachments/TestAttachmentWidget.h new file mode 100644 index 000000000..4367234cd --- /dev/null +++ b/tests/gui/attachments/TestAttachmentWidget.h @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2025 KeePassXC Team + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 or (at your option) + * version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once + +#include + +#include +#include + +class TestAttachmentsWidget : public QObject +{ + Q_OBJECT + +private slots: + void initTestCase(); + + void testTextAttachment(); + void testImageAttachment(); + void testUnknownAttachment(); + +private: + QScopedPointer m_attachmentWidget; +}; diff --git a/tests/gui/attachments/TestAttachmentsGui.cpp b/tests/gui/attachments/TestAttachmentsGui.cpp new file mode 100644 index 000000000..b0f29dfc2 --- /dev/null +++ b/tests/gui/attachments/TestAttachmentsGui.cpp @@ -0,0 +1,46 @@ +#include + +#include "TestAttachmentWidget.h" +#include "TestEditEntryAttachmentsDialog.h" +#include "TestImageAttachmentsView.h" +#include "TestImageAttachmentsWidget.h" +#include "TestPreviewEntryAttachmentsDialog.h" +#include "TestTextAttachmentsEditWidget.h" +#include "TestTextAttachmentsPreviewWidget.h" +#include "TestTextAttachmentsWidget.h" + +#include +#include + +int main(int argc, char* argv[]) +{ + QApplication::setAttribute(Qt::AA_EnableHighDpiScaling); + QGuiApplication::setAttribute(Qt::AA_UseHighDpiPixmaps); + Application app(argc, argv); + app.setApplicationName("KeePassXC"); + app.setApplicationVersion(KEEPASSXC_VERSION); + app.setQuitOnLastWindowClosed(false); + app.setAttribute(Qt::AA_Use96Dpi, true); + app.applyTheme(); + + TestPreviewEntryAttachmentsDialog previewDialogTest{}; + TestEditEntryAttachmentsDialog editDialogTest{}; + TestTextAttachmentsWidget textAttachmentsWidget{}; + TestTextAttachmentsPreviewWidget textPreviewWidget{}; + TestTextAttachmentsEditWidget textEditWidget{}; + TestImageAttachmentsWidget imageWidget{}; + TestImageAttachmentsView imageView{}; + TestAttachmentsWidget attachmentWidget{}; + + int result = 0; + result |= QTest::qExec(&previewDialogTest, argc, argv); + result |= QTest::qExec(&editDialogTest, argc, argv); + result |= QTest::qExec(&textAttachmentsWidget, argc, argv); + result |= QTest::qExec(&textPreviewWidget, argc, argv); + result |= QTest::qExec(&textEditWidget, argc, argv); + result |= QTest::qExec(&imageWidget, argc, argv); + result |= QTest::qExec(&imageView, argc, argv); + result |= QTest::qExec(&attachmentWidget, argc, argv); + + return result; +} diff --git a/tests/gui/attachments/TestEditEntryAttachmentsDialog.cpp b/tests/gui/attachments/TestEditEntryAttachmentsDialog.cpp new file mode 100644 index 000000000..0353b6a6f --- /dev/null +++ b/tests/gui/attachments/TestEditEntryAttachmentsDialog.cpp @@ -0,0 +1,95 @@ +#include "TestEditEntryAttachmentsDialog.h" + +#include + +#include + +#include +#include +#include +#include +#include +#include +#include + +void TestEditEntryAttachmentsDialog::initTestCase() +{ + m_editDialog.reset(new EditEntryAttachmentsDialog()); + + QVERIFY(m_editDialog); +} + +void TestEditEntryAttachmentsDialog::testSetAttachment() +{ + const attachments::Attachment Test{.name = "text.txt", .data = "Test"}; + m_editDialog->setAttachment(Test); + + QCoreApplication::processEvents(); + + QVERIFY2(m_editDialog->windowTitle().contains(Test.name), "Expected file name in the title"); + + auto layout = m_editDialog->findChild("verticalLayout"); + QVERIFY2(layout, "QVBoxLayout not found"); + QCOMPARE(layout->count(), 2); + + auto widget = qobject_cast(layout->itemAt(0)->widget()); + QVERIFY2(widget, "Expected AttachmentWidget"); + + auto sizePolicy = widget->sizePolicy(); + QCOMPARE(sizePolicy.horizontalPolicy(), QSizePolicy::Expanding); + QCOMPARE(sizePolicy.verticalPolicy(), QSizePolicy::Expanding); + + auto attachments = widget->getAttachment(); + + QCOMPARE(attachments.name, Test.name); + QCOMPARE(attachments.data, Test.data); +} + +void TestEditEntryAttachmentsDialog::testSetAttachmentTwice() +{ + const attachments::Attachment TestText{.name = "text.txt", .data = "Test"}; + m_editDialog->setAttachment(TestText); + + QCoreApplication::processEvents(); + + const attachments::Attachment TestImage{ + .name = "test.jpg", .data = QByteArray::fromHex("FFD8FFE000104A46494600010101006000600000FFD9")}; + m_editDialog->setAttachment(TestImage); + + QCoreApplication::processEvents(); + + QVERIFY2(m_editDialog->windowTitle().contains(TestImage.name), "Expected file name in the title"); + + auto layout = m_editDialog->findChild("verticalLayout"); + QVERIFY2(layout, "QVBoxLayout not found"); + QCOMPARE(layout->count(), 2); + + auto widget = qobject_cast(layout->itemAt(0)->widget()); + QVERIFY2(widget, "Expected AttachmentWidget"); + + auto attachments = widget->getAttachment(); + + QCOMPARE(attachments.name, TestImage.name); + QCOMPARE(attachments.data, TestImage.data); +} + +void TestEditEntryAttachmentsDialog::testBottonsBox() +{ + const attachments::Attachment TestText{.name = "text.txt", .data = "Test"}; + m_editDialog->setAttachment(TestText); + + QCoreApplication::processEvents(); + + QSignalSpy acceptButton(m_editDialog.data(), &PreviewEntryAttachmentsDialog::accepted); + QSignalSpy closeButton(m_editDialog.data(), &PreviewEntryAttachmentsDialog::rejected); + + auto buttonsBox = m_editDialog->findChild(); + QVERIFY2(buttonsBox, "ButtonsBox not found"); + + for (auto button : buttonsBox->buttons()) { + QTest::mouseClick(button, Qt::LeftButton); + } + + QCOMPARE(acceptButton.count(), 1); + QCOMPARE(closeButton.count(), 1); +} diff --git a/tests/gui/attachments/TestEditEntryAttachmentsDialog.h b/tests/gui/attachments/TestEditEntryAttachmentsDialog.h new file mode 100644 index 000000000..76f3ac2ff --- /dev/null +++ b/tests/gui/attachments/TestEditEntryAttachmentsDialog.h @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2025 KeePassXC Team + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 or (at your option) + * version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once + +#include "EditEntryAttachmentsDialog.h" + +#include +#include + +class TestEditEntryAttachmentsDialog : public QObject +{ + Q_OBJECT + +private slots: + void initTestCase(); + + void testSetAttachment(); + void testSetAttachmentTwice(); + + void testBottonsBox(); + +private: + QScopedPointer m_editDialog{}; +}; diff --git a/tests/gui/attachments/TestImageAttachmentsView.cpp b/tests/gui/attachments/TestImageAttachmentsView.cpp new file mode 100644 index 000000000..0d3ffed00 --- /dev/null +++ b/tests/gui/attachments/TestImageAttachmentsView.cpp @@ -0,0 +1,76 @@ +#include "TestImageAttachmentsView.h" + +#include + +#include +#include +#include +#include +#include + +void TestImageAttachmentsView::initTestCase() +{ + m_view.reset(new ImageAttachmentsView()); + + // Generate the black rectange. + QImage image(1000, 1000, QImage::Format_RGB32); + image.fill(Qt::black); + + auto scene = new QGraphicsScene(); + scene->addPixmap(QPixmap::fromImage(image)); + + m_view->setScene(scene); + m_view->show(); + + QCoreApplication::processEvents(); +} + +void TestImageAttachmentsView::testEmitWheelEvent() +{ + QSignalSpy ctrlWheelEvent{m_view.data(), &ImageAttachmentsView::ctrlWheelEvent}; + + QPoint center = m_view->rect().center(); + + m_view->setFocus(); + + QWheelEvent event(center, // local pos + m_view->mapToGlobal(center), // global pos + QPoint(0, 0), + QPoint(0, 120), + Qt::NoButton, + Qt::ControlModifier, + Qt::ScrollBegin, + false); + + QCoreApplication::sendEvent(m_view->viewport(), &event); + + QCOMPARE(ctrlWheelEvent.count(), 1); +} + +void TestImageAttachmentsView::testEnableFit() +{ + m_view->enableAutoFitInView(); + QVERIFY(m_view->isAutoFitInViewActivated()); + + const auto oldTransform = m_view->transform(); + + m_view->resize(m_view->size() + QSize(100, 100)); + + QCoreApplication::processEvents(); + + QVERIFY(m_view->transform() != oldTransform); +} + +void TestImageAttachmentsView::testDisableFit() +{ + m_view->disableAutoFitInView(); + QVERIFY(!m_view->isAutoFitInViewActivated()); + + const auto expectedTransform = m_view->transform(); + + m_view->resize(m_view->size() + QSize(100, 100)); + + QCoreApplication::processEvents(); + + QCOMPARE(m_view->transform(), expectedTransform); +} diff --git a/tests/gui/attachments/TestImageAttachmentsView.h b/tests/gui/attachments/TestImageAttachmentsView.h new file mode 100644 index 000000000..06f8c58d3 --- /dev/null +++ b/tests/gui/attachments/TestImageAttachmentsView.h @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2025 KeePassXC Team + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 or (at your option) + * version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once + +#include + +#include +#include + +class TestImageAttachmentsView : public QObject +{ + Q_OBJECT + +private slots: + void initTestCase(); + + void testEmitWheelEvent(); + void testEnableFit(); + void testDisableFit(); + +private: + QScopedPointer m_view{}; +}; diff --git a/tests/gui/attachments/TestImageAttachmentsWidget.cpp b/tests/gui/attachments/TestImageAttachmentsWidget.cpp new file mode 100644 index 000000000..fc2d14e2d --- /dev/null +++ b/tests/gui/attachments/TestImageAttachmentsWidget.cpp @@ -0,0 +1,244 @@ +#include "TestImageAttachmentsWidget.h" + +#include +#include + +#include +#include +#include +#include +#include + +void TestImageAttachmentsWidget::initTestCase() +{ + m_widget.reset(new ImageAttachmentsWidget()); + m_zoomCombobox = m_widget->findChild("zoomComboBox"); + QVERIFY(m_zoomCombobox); + + m_imageAttachmentsView = m_widget->findChild("imagesView"); + QVERIFY(m_imageAttachmentsView); + + // Generate the black rectange. + QImage image(1000, 1000, QImage::Format_RGB32); + image.fill(Qt::black); + + QByteArray imageBytes{}; + QBuffer buffer(&imageBytes); + buffer.open(QIODevice::WriteOnly); + + image.save(&buffer, "PNG"); + + m_widget->openAttachment({.name = "black.png", .data = std::move(imageBytes)}, attachments::OpenMode::ReadOnly); + + m_widget->show(); + + QCoreApplication::processEvents(); +} + +void TestImageAttachmentsWidget::testFitInView() +{ + QCOMPARE(m_zoomCombobox->currentText(), tr("Fit")); + QVERIFY(m_imageAttachmentsView->isAutoFitInViewActivated()); + + auto zoomFactor = m_imageAttachmentsView->transform(); + + m_widget->setMinimumSize(m_widget->size() + QSize{100, 100}); + + QCoreApplication::processEvents(); + + QVERIFY(zoomFactor != m_imageAttachmentsView->transform()); +} + +void TestImageAttachmentsWidget::testZoomCombobox() +{ + for (const auto zoom : {0.25, 0.5, 1.0, 2.0}) { + auto index = m_zoomCombobox->findData(zoom); + QVERIFY(index != -1); + + m_zoomCombobox->setCurrentIndex(index); + + QCoreApplication::processEvents(); + + QCOMPARE(m_imageAttachmentsView->transform(), QTransform::fromScale(zoom, zoom)); + } +} + +void TestImageAttachmentsWidget::testEditZoomCombobox() +{ + for (double i = 0.25; i < 5; i += 0.25) { + m_zoomCombobox->setCurrentText(QString::number(i * 100)); + + QCoreApplication::processEvents(); + + QCOMPARE(m_imageAttachmentsView->transform(), QTransform::fromScale(i, i)); + } +} + +void TestImageAttachmentsWidget::testEditWithPercentZoomCombobox() +{ + // Example 100 % + for (double i = 0.25; i < 5; i += 0.25) { + m_zoomCombobox->setCurrentText(QString("%1 %").arg(i * 100)); + + QCoreApplication::processEvents(); + + QCOMPARE(m_imageAttachmentsView->transform(), QTransform::fromScale(i, i)); + } + + // Example 100% + for (double i = 0.25; i < 5; i += 0.25) { + m_zoomCombobox->setCurrentText(QString("%1%").arg(i * 100)); + + QCoreApplication::processEvents(); + + QCOMPARE(m_imageAttachmentsView->transform(), QTransform::fromScale(i, i)); + } +} + +void TestImageAttachmentsWidget::testInvalidValueZoomCombobox() +{ + auto index = m_zoomCombobox->findData(1.0); + QVERIFY(index != -1); + + m_zoomCombobox->setCurrentIndex(index); + + QCoreApplication::processEvents(); + + const QTransform expectedTransform = m_imageAttachmentsView->transform(); + + for (const auto& invalidValue : {"Help", "3,4", "", ".", "% 100"}) { + m_zoomCombobox->setCurrentText(invalidValue); + + QCoreApplication::processEvents(); + + QCOMPARE(m_imageAttachmentsView->transform(), expectedTransform); + } +} + +void TestImageAttachmentsWidget::testZoomInByMouse() +{ + QPoint center = m_imageAttachmentsView->rect().center(); + + // Set zoom: 100% + auto index = m_zoomCombobox->findData(1.0); + QVERIFY(index != -1); + m_zoomCombobox->setCurrentIndex(index); + + m_imageAttachmentsView->setFocus(); + + QCoreApplication::processEvents(); + + const auto transform = m_imageAttachmentsView->transform(); + + QWheelEvent event(center, // local pos + m_imageAttachmentsView->mapToGlobal(center), // global pos + QPoint(0, 0), + QPoint(0, 120), + Qt::NoButton, + Qt::ControlModifier, + Qt::ScrollBegin, + false); + + QCoreApplication::sendEvent(m_imageAttachmentsView->viewport(), &event); + + QCoreApplication::processEvents(); + + QTransform t = m_imageAttachmentsView->transform(); + QVERIFY(t.m11() > transform.m11()); + QVERIFY(t.m22() > transform.m22()); +} + +void TestImageAttachmentsWidget::testZoomOutByMouse() +{ + QPoint center = m_imageAttachmentsView->rect().center(); + + // Set zoom: 100% + auto index = m_zoomCombobox->findData(1.0); + QVERIFY(index != -1); + m_zoomCombobox->setCurrentIndex(index); + + m_imageAttachmentsView->setFocus(); + + QCoreApplication::processEvents(); + + const auto transform = m_imageAttachmentsView->transform(); + + QWheelEvent event(center, // local pos + center, // global pos + QPoint(0, 0), + QPoint(0, -120), + Qt::NoButton, + Qt::ControlModifier, + Qt::ScrollBegin, + true); + + QCoreApplication::sendEvent(m_imageAttachmentsView->viewport(), &event); + + QCoreApplication::processEvents(); + + QTransform t = m_imageAttachmentsView->transform(); + QVERIFY(t.m11() < transform.m11()); + QVERIFY(t.m22() < transform.m22()); +} + +void TestImageAttachmentsWidget::testZoomLowerBound() +{ + m_widget->setMinimumSize(100, 100); + + QCoreApplication::processEvents(); + + auto minFactor = m_imageAttachmentsView->calculateFitInViewFactor(); + + // Set size less then minFactor + m_zoomCombobox->setCurrentText(QString::number((minFactor * 100.0) / 2)); + + QCoreApplication::processEvents(); + + const auto expectTransform = m_imageAttachmentsView->transform(); + + QPoint center = m_imageAttachmentsView->rect().center(); + + QWheelEvent event(center, // local pos + center, // global pos + QPoint(0, 0), + QPoint(0, -120), + Qt::NoButton, + Qt::ControlModifier, + Qt::ScrollBegin, + true); + + QCoreApplication::sendEvent(m_imageAttachmentsView->viewport(), &event); + + QCoreApplication::processEvents(); + + QCOMPARE(m_imageAttachmentsView->transform(), expectTransform); +} + +void TestImageAttachmentsWidget::testZoomUpperBound() +{ + m_widget->setMinimumSize(100, 100); + + // Set size less then minFactor + m_zoomCombobox->setCurrentText(QString::number(500)); + + QCoreApplication::processEvents(); + + const auto expectTransform = m_imageAttachmentsView->transform(); + + QPoint center = m_imageAttachmentsView->rect().center(); + + QWheelEvent event(center, // local pos + center, // global pos + QPoint(0, 0), + QPoint(0, 120), + Qt::NoButton, + Qt::ControlModifier, + Qt::ScrollBegin, + true); + + QCoreApplication::sendEvent(m_imageAttachmentsView->viewport(), &event); + + QCoreApplication::processEvents(); + + QCOMPARE(m_imageAttachmentsView->transform(), expectTransform); +} diff --git a/tests/gui/attachments/TestImageAttachmentsWidget.h b/tests/gui/attachments/TestImageAttachmentsWidget.h new file mode 100644 index 000000000..6f27be2f6 --- /dev/null +++ b/tests/gui/attachments/TestImageAttachmentsWidget.h @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2025 KeePassXC Team + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 or (at your option) + * version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once + +#include + +#include +#include +#include + +class ImageAttachmentsView; + +class TestImageAttachmentsWidget : public QObject +{ + Q_OBJECT + +private slots: + void initTestCase(); + + void testFitInView(); + void testZoomCombobox(); + void testEditZoomCombobox(); + void testEditWithPercentZoomCombobox(); + void testInvalidValueZoomCombobox(); + void testZoomInByMouse(); + void testZoomOutByMouse(); + void testZoomLowerBound(); + void testZoomUpperBound(); + +private: + QScopedPointer m_widget{}; + QPointer m_zoomCombobox{}; + QPointer m_imageAttachmentsView{}; +}; diff --git a/tests/gui/attachments/TestPreviewEntryAttachmentsDialog.cpp b/tests/gui/attachments/TestPreviewEntryAttachmentsDialog.cpp new file mode 100644 index 000000000..ca0d6ce20 --- /dev/null +++ b/tests/gui/attachments/TestPreviewEntryAttachmentsDialog.cpp @@ -0,0 +1,97 @@ +#include "TestPreviewEntryAttachmentsDialog.h" + +#include + +#include + +#include +#include +#include +#include +#include +#include +#include + +void TestPreviewEntryAttachmentsDialog::initTestCase() +{ + m_previewDialog.reset(new PreviewEntryAttachmentsDialog()); + + QVERIFY(m_previewDialog); +} + +void TestPreviewEntryAttachmentsDialog::testSetAttachment() +{ + const attachments::Attachment Test{.name = "text.txt", .data = "Test"}; + m_previewDialog->setAttachment(Test); + + QCoreApplication::processEvents(); + + QVERIFY2(m_previewDialog->windowTitle().contains(Test.name), "Expected file name in the title"); + + auto layout = m_previewDialog->findChild("verticalLayout"); + QVERIFY2(layout, "QVBoxLayout not found"); + QCOMPARE(layout->count(), 2); + + auto widget = qobject_cast(layout->itemAt(0)->widget()); + QVERIFY2(widget, "Expected AbstractAttachmentWidget"); + + auto sizePolicy = widget->sizePolicy(); + QCOMPARE(sizePolicy.horizontalPolicy(), QSizePolicy::Expanding); + QCOMPARE(sizePolicy.verticalPolicy(), QSizePolicy::Expanding); + + auto attachments = widget->getAttachment(); + + QCOMPARE(attachments.name, Test.name); + QCOMPARE(attachments.data, Test.data); +} + +void TestPreviewEntryAttachmentsDialog::testSetAttachmentTwice() +{ + const attachments::Attachment TestText{.name = "text.txt", .data = "Test"}; + m_previewDialog->setAttachment(TestText); + + QCoreApplication::processEvents(); + + const attachments::Attachment TestImage{ + .name = "test.jpg", .data = QByteArray::fromHex("FFD8FFE000104A46494600010101006000600000FFD9")}; + m_previewDialog->setAttachment(TestImage); + + QCoreApplication::processEvents(); + + QVERIFY2(m_previewDialog->windowTitle().contains(TestImage.name), "Expected file name in the title"); + + auto layout = m_previewDialog->findChild("verticalLayout"); + QVERIFY2(layout, "QVBoxLayout not found"); + QCOMPARE(layout->count(), 2); + + auto widget = qobject_cast(layout->itemAt(0)->widget()); + QVERIFY2(widget, "Expected AbstractAttachmentWidget"); + + auto attachments = widget->getAttachment(); + + QCOMPARE(attachments.name, TestImage.name); + QCOMPARE(attachments.data, TestImage.data); +} + +void TestPreviewEntryAttachmentsDialog::testBottonsBox() +{ + const attachments::Attachment TestText{.name = "text.txt", .data = "Test"}; + m_previewDialog->setAttachment(TestText); + + QCoreApplication::processEvents(); + + QSignalSpy saveButton(m_previewDialog.data(), &PreviewEntryAttachmentsDialog::saveAttachment); + QSignalSpy openButton(m_previewDialog.data(), &PreviewEntryAttachmentsDialog::openAttachment); + QSignalSpy closeButton(m_previewDialog.data(), &PreviewEntryAttachmentsDialog::rejected); + + auto buttonsBox = m_previewDialog->findChild("dialogButtons"); + QVERIFY2(buttonsBox, "ButtonsBox not found"); + + for (auto button : buttonsBox->buttons()) { + QTest::mouseClick(button, Qt::LeftButton); + } + + QCOMPARE(saveButton.count(), 1); + QCOMPARE(openButton.count(), 1); + QCOMPARE(closeButton.count(), 1); +} diff --git a/tests/gui/attachments/TestPreviewEntryAttachmentsDialog.h b/tests/gui/attachments/TestPreviewEntryAttachmentsDialog.h new file mode 100644 index 000000000..7b5899b9e --- /dev/null +++ b/tests/gui/attachments/TestPreviewEntryAttachmentsDialog.h @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2025 KeePassXC Team + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 or (at your option) + * version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once + +#include "PreviewEntryAttachmentsDialog.h" + +#include + +#include + +class TestPreviewEntryAttachmentsDialog : public QObject +{ + Q_OBJECT + +private slots: + void initTestCase(); + + void testSetAttachment(); + void testSetAttachmentTwice(); + + void testBottonsBox(); + +private: + QScopedPointer m_previewDialog{}; +}; diff --git a/tests/gui/attachments/TestTextAttachmentsEditWidget.cpp b/tests/gui/attachments/TestTextAttachmentsEditWidget.cpp new file mode 100644 index 000000000..963533bd7 --- /dev/null +++ b/tests/gui/attachments/TestTextAttachmentsEditWidget.cpp @@ -0,0 +1,49 @@ +#include "TestTextAttachmentsEditWidget.h" + +#include + +#include +#include +#include +#include +#include +#include +#include + +void TestTextAttachmentsEditWidget::initTestCase() +{ + m_widget.reset(new TextAttachmentsEditWidget()); +} + +void TestTextAttachmentsEditWidget::testEmitTextChanged() +{ + QSignalSpy textChangedSignal(m_widget.data(), &TextAttachmentsEditWidget::textChanged); + + m_widget->openAttachment({.name = "test.txt", .data = {}}, attachments::OpenMode::ReadWrite); + + QCoreApplication::processEvents(); + + auto textEdit = m_widget->findChild("attachmentsTextEdit"); + QVERIFY(textEdit); + + const QByteArray NewText = "New test text"; + textEdit->setText(NewText); + + QVERIFY(textChangedSignal.count() > 0); +} + +void TestTextAttachmentsEditWidget::testEmitPreviewButtonClicked() +{ + QSignalSpy previwButtonClickedSignal(m_widget.data(), &TextAttachmentsEditWidget::previewButtonClicked); + + m_widget->openAttachment({.name = "test.txt", .data = {}}, attachments::OpenMode::ReadWrite); + + QCoreApplication::processEvents(); + + auto previewButton = m_widget->findChild("previewPushButton"); + QVERIFY(previewButton); + + QTest::mouseClick(previewButton, Qt::LeftButton); + + QCOMPARE(previwButtonClickedSignal.count(), 1); +} diff --git a/tests/gui/attachments/TestTextAttachmentsEditWidget.h b/tests/gui/attachments/TestTextAttachmentsEditWidget.h new file mode 100644 index 000000000..3d89f2a2e --- /dev/null +++ b/tests/gui/attachments/TestTextAttachmentsEditWidget.h @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2025 KeePassXC Team + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 or (at your option) + * version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once + +#include + +#include +#include + +class TestTextAttachmentsEditWidget : public QObject +{ + Q_OBJECT + +private slots: + void initTestCase(); + + void testEmitTextChanged(); + void testEmitPreviewButtonClicked(); + +private: + QScopedPointer m_widget{}; +}; diff --git a/tests/gui/attachments/TestTextAttachmentsPreviewWidget.cpp b/tests/gui/attachments/TestTextAttachmentsPreviewWidget.cpp new file mode 100644 index 000000000..0ddea53e3 --- /dev/null +++ b/tests/gui/attachments/TestTextAttachmentsPreviewWidget.cpp @@ -0,0 +1,40 @@ +#include "TestTextAttachmentsPreviewWidget.h" + +#include + +#include +#include + +void TestTextAttachmentsPreviewWidget::initTestCase() +{ + m_widget.reset(new TextAttachmentsPreviewWidget()); +} + +void TestTextAttachmentsPreviewWidget::testDetectMimeByFile() +{ + const auto combobox = m_widget->findChild("typeComboBox"); + QVERIFY(combobox); + + const attachments::Attachment Text{.name = "test.txt", .data = {}}; + m_widget->openAttachment(Text, attachments::OpenMode::ReadOnly); + + QCoreApplication::processEvents(); + + QCOMPARE(combobox->currentData().toInt(), TextAttachmentsPreviewWidget::PlainText); + + const attachments::Attachment Html{.name = "test.html", .data = {}}; + m_widget->openAttachment(Html, attachments::OpenMode::ReadOnly); + + QCoreApplication::processEvents(); + + QCOMPARE(combobox->currentData().toInt(), TextAttachmentsPreviewWidget::Html); + +#if (QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)) + const attachments::Attachment Markdown{.name = "test.md", .data = {}}; + m_widget->openAttachment(Markdown, attachments::OpenMode::ReadOnly); + + QCoreApplication::processEvents(); + + QCOMPARE(combobox->currentData().toInt(), TextAttachmentsPreviewWidget::Markdown); +#endif +} diff --git a/tests/gui/attachments/TestTextAttachmentsPreviewWidget.h b/tests/gui/attachments/TestTextAttachmentsPreviewWidget.h new file mode 100644 index 000000000..8e34a8d9b --- /dev/null +++ b/tests/gui/attachments/TestTextAttachmentsPreviewWidget.h @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2025 KeePassXC Team + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 or (at your option) + * version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once + +#include + +#include +#include + +class TestTextAttachmentsPreviewWidget : public QObject +{ + Q_OBJECT + +private slots: + void initTestCase(); + + void testDetectMimeByFile(); + +private: + QScopedPointer m_widget{}; +}; diff --git a/tests/gui/attachments/TestTextAttachmentsWidget.cpp b/tests/gui/attachments/TestTextAttachmentsWidget.cpp new file mode 100644 index 000000000..bba6f9840 --- /dev/null +++ b/tests/gui/attachments/TestTextAttachmentsWidget.cpp @@ -0,0 +1,224 @@ +#include "TestTextAttachmentsWidget.h" + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +void TestTextAttachmentsWidget::initTestCase() +{ + m_textWidget.reset(new TextAttachmentsWidget()); +} + +void TestTextAttachmentsWidget::testInitTextWidget() +{ + auto splitter = m_textWidget->findChild(); + QVERIFY2(splitter, "Splitter not found"); + + QCOMPARE(splitter->count(), 2); + QVERIFY2(qobject_cast(splitter->widget(0)), "EditTextWidget not found"); + QVERIFY2(qobject_cast(splitter->widget(1)), "PreviewTextWidget not found"); +} + +void TestTextAttachmentsWidget::testTextReadWriteWidget() +{ + const attachments::Attachment Test{.name = "text.txt", .data = "Test"}; + m_textWidget->openAttachment(Test, attachments::OpenMode::ReadWrite); + m_textWidget->show(); + + QCoreApplication::processEvents(); + + auto splitter = m_textWidget->findChild(); + QVERIFY2(splitter, "Splitter not found"); + auto sizes = splitter->sizes(); + QCOMPARE(sizes.size(), 2); + QVERIFY2(sizes[0] > 0, "EditTextWidget width must be greater than zero"); + + QCOMPARE(sizes[1], 0); + + auto widget = qobject_cast(splitter->widget(0)); + QVERIFY(widget); + auto attachments = widget->getAttachment(); + + QCOMPARE(attachments.name, Test.name); + QCOMPARE(attachments.data, Test.data); + + auto previewWidget = qobject_cast(splitter->widget(1)); + QVERIFY(previewWidget); + attachments = previewWidget->getAttachment(); + + QCOMPARE(attachments.name, Test.name); + QCOMPARE(attachments.data, Test.data); +} + +void TestTextAttachmentsWidget::testTextReadWidget() +{ + const attachments::Attachment Test{.name = "text.txt", .data = "Test"}; + m_textWidget->openAttachment(Test, attachments::OpenMode::ReadOnly); + m_textWidget->show(); + + QCoreApplication::processEvents(); + + auto splitter = m_textWidget->findChild(); + QVERIFY2(splitter, "Splitter not found"); + auto sizes = splitter->sizes(); + QCOMPARE(sizes.size(), 2); + QVERIFY2(sizes[1] > 0, "PreviewTextWidget width must be greater then zero"); + + QVERIFY(splitter->widget(0)->isHidden()); + + auto widget = qobject_cast(splitter->widget(0)); + QVERIFY(widget); + auto attachments = widget->getAttachment(); + + QCOMPARE(attachments.name, Test.name); + QCOMPARE(attachments.data, Test.data); + + auto previewWidget = qobject_cast(splitter->widget(1)); + QVERIFY(previewWidget); + attachments = previewWidget->getAttachment(); + + QCOMPARE(attachments.name, Test.name); + QCOMPARE(attachments.data, Test.data); +} + +void TestTextAttachmentsWidget::testTextChanged() +{ + const attachments::Attachment Test{.name = "text.txt", .data = "Test"}; + m_textWidget->openAttachment(Test, attachments::OpenMode::ReadWrite); + + QCoreApplication::processEvents(); + + auto splitter = m_textWidget->findChild(); + QVERIFY2(splitter, "Splitter not found"); + QCOMPARE(splitter->sizes().size(), 2); + + auto editWidget = qobject_cast(splitter->widget(0)); + QVERIFY2(editWidget, "Edit widget not found"); + + auto textEdit = editWidget->findChild(); + QVERIFY(textEdit); + + const QByteArray NewText = "New test text"; + textEdit->setText(NewText); + + QCoreApplication::processEvents(); + + auto attachments = m_textWidget->getAttachment(); + + QCOMPARE(attachments.data, NewText); +} + +void TestTextAttachmentsWidget::testTextChangedInReadOnlyMode() +{ + const attachments::Attachment Test{.name = "text.txt", .data = "Test"}; + m_textWidget->openAttachment(Test, attachments::OpenMode::ReadOnly); + + QCoreApplication::processEvents(); + + auto splitter = m_textWidget->findChild(); + QVERIFY2(splitter, "Splitter not found"); + QCOMPARE(splitter->sizes().size(), 2); + + auto editWidget = qobject_cast(splitter->widget(0)); + QVERIFY2(editWidget, "Edit widget not found"); + + auto textEdit = editWidget->findChild(); + QVERIFY(textEdit); + + const QByteArray NewText = "New test text"; + textEdit->setText(NewText); + + QCoreApplication::processEvents(); + + auto attachments = m_textWidget->getAttachment(); + + QCOMPARE(attachments.data, Test.data); +} + +void TestTextAttachmentsWidget::testPreviewTextChanged() +{ + const attachments::Attachment Test{.name = "text.txt", .data = "Test"}; + + auto previewTimer = m_textWidget->findChild(); + QVERIFY2(previewTimer, "PreviewTimer not found!"); + + QSignalSpy timeout(previewTimer, &QTimer::timeout); + + m_textWidget->openAttachment(Test, attachments::OpenMode::ReadWrite); + + // Waiting for the first timeout + while (timeout.count() < 1) { + QCoreApplication::processEvents(QEventLoop::AllEvents, 50); + } + + auto splitter = m_textWidget->findChild(); + QVERIFY2(splitter, "Splitter not found"); + QCOMPARE(splitter->sizes().size(), 2); + + splitter->setSizes({1, 1}); + + QCoreApplication::processEvents(); + + auto editWidget = qobject_cast(splitter->widget(0)); + QVERIFY2(editWidget, "Edit widget not found"); + + auto textEdit = editWidget->findChild(); + QVERIFY(textEdit); + + const QByteArray NewText = "New test text"; + textEdit->setText(NewText); + + // Waiting for the second timeout + while (timeout.count() < 2) { + QCoreApplication::processEvents(QEventLoop::AllEvents, 50); + } + + auto previewWidget = qobject_cast(splitter->widget(1)); + auto attachments = previewWidget->getAttachment(); + + QCOMPARE(attachments.data, NewText); +} + +void TestTextAttachmentsWidget::testOpenPreviewButton() +{ + const attachments::Attachment Test{.name = "text.txt", .data = "Test"}; + m_textWidget->openAttachment(Test, attachments::OpenMode::ReadWrite); + m_textWidget->show(); + + QCoreApplication::processEvents(); + + auto splitter = m_textWidget->findChild(); + QVERIFY2(splitter, "Splitter not found"); + QCOMPARE(splitter->sizes().size(), 2); + + auto editWidget = qobject_cast(splitter->widget(0)); + QVERIFY2(editWidget, "Edit widget not found"); + QVERIFY(editWidget->isVisible()); + + auto previewButton = editWidget->findChild("previewPushButton"); + + auto sizes = splitter->sizes(); + QVERIFY(sizes[0] > 0); + QCOMPARE(sizes[1], 0); + + QTest::mouseClick(previewButton, Qt::LeftButton); + + sizes = splitter->sizes(); + QCOMPARE(sizes.size(), 2); + QVERIFY(sizes[0] > 0); + QVERIFY(sizes[1] > 0); + + QTest::mouseClick(previewButton, Qt::LeftButton); + sizes = splitter->sizes(); + QCOMPARE(sizes.size(), 2); + QVERIFY(sizes[0] > 0); + QCOMPARE(sizes[1], 0); +} diff --git a/tests/gui/attachments/TestTextAttachmentsWidget.h b/tests/gui/attachments/TestTextAttachmentsWidget.h new file mode 100644 index 000000000..3c8198dfa --- /dev/null +++ b/tests/gui/attachments/TestTextAttachmentsWidget.h @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2025 KeePassXC Team + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 or (at your option) + * version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once + +#include + +#include +#include + +class TestTextAttachmentsWidget : public QObject +{ + Q_OBJECT + +private slots: + void initTestCase(); + + void testInitTextWidget(); + void testTextReadWriteWidget(); + void testTextReadWidget(); + void testOpenPreviewButton(); + void testPreviewTextChanged(); + void testTextChanged(); + void testTextChangedInReadOnlyMode(); + +private: + QScopedPointer m_textWidget; +}; diff --git a/tests/mock/MockRemoteProcess.cpp b/tests/mock/MockRemoteProcess.cpp new file mode 100644 index 000000000..fe1770932 --- /dev/null +++ b/tests/mock/MockRemoteProcess.cpp @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2023 KeePassXC Team + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 or (at your option) + * version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include + +#include "MockRemoteProcess.h" + +MockRemoteProcess::MockRemoteProcess(QObject* parent, QString dbPath) + : RemoteProcess(parent) + , m_dbPath(std::move(dbPath)) +{ +} + +void MockRemoteProcess::start(const QString&) +{ + QFile::copy(m_dbPath, m_tempFileLocation); +} + +qint64 MockRemoteProcess::write(const QString& data) +{ + m_data.append(data.toUtf8()); + return data.length(); +} + +bool MockRemoteProcess::waitForBytesWritten() +{ + return true; +} + +void MockRemoteProcess::closeWriteChannel() +{ + // nothing to do +} + +bool MockRemoteProcess::waitForFinished(int) +{ + return true; // no need to wait +} + +int MockRemoteProcess::exitCode() const +{ + return 0; // always return success +} + +QString MockRemoteProcess::readOutput() +{ + return {}; +} + +QString MockRemoteProcess::readError() +{ + return {}; +} diff --git a/tests/mock/MockRemoteProcess.h b/tests/mock/MockRemoteProcess.h new file mode 100644 index 000000000..c39b50cdf --- /dev/null +++ b/tests/mock/MockRemoteProcess.h @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2023 KeePassXC Team + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 or (at your option) + * version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef KEEPASSXC_MOCKREMOTEPROCESS_H +#define KEEPASSXC_MOCKREMOTEPROCESS_H + +#include "gui/remote/RemoteProcess.h" + +class MockRemoteProcess : public RemoteProcess +{ +public: + explicit MockRemoteProcess(QObject* parent, QString dbPath); + ~MockRemoteProcess() override = default; + + void start(const QString& program) override; + qint64 write(const QString& data) override; + bool waitForBytesWritten() override; + void closeWriteChannel() override; + bool waitForFinished(int msecs) override; + [[nodiscard]] int exitCode() const override; + virtual QString readOutput() override; + virtual QString readError() override; + +private: + QByteArray m_data; + QString m_dbPath; +}; + +#endif // KEEPASSXC_MOCKREMOTEPROCESS_H diff --git a/tests/modeltest.cpp b/tests/modeltest.cpp index 8f7c95484..abbe546fa 100644 --- a/tests/modeltest.cpp +++ b/tests/modeltest.cpp @@ -452,12 +452,12 @@ void ModelTest::data() } // General Purpose roles that should return a QColor - QVariant colorVariant = model->data ( model->index ( 0, 0 ), Qt::BackgroundColorRole ); + QVariant colorVariant = model->data ( model->index ( 0, 0 ), Qt::BackgroundRole ); if ( colorVariant.isValid() ) { QVERIFY( colorVariant.canConvert() ); } - colorVariant = model->data ( model->index ( 0, 0 ), Qt::TextColorRole ); + colorVariant = model->data ( model->index ( 0, 0 ), Qt::ForegroundRole ); if ( colorVariant.isValid() ) { QVERIFY( colorVariant.canConvert() ); } diff --git a/tests/util/TemporaryFile.cpp b/tests/util/TemporaryFile.cpp index 413f03305..987852097 100644 --- a/tests/util/TemporaryFile.cpp +++ b/tests/util/TemporaryFile.cpp @@ -17,6 +17,29 @@ #include "TemporaryFile.h" +#include +#include +#include + +namespace +{ + QPointer g_tempConfigFile; +} + +QString TemporaryFile::createTempConfigFile() +{ + if (!qApp) { + Q_ASSERT(false); + return {}; + } + if (g_tempConfigFile) { + delete g_tempConfigFile; + } + auto tmpFileName = QString("%1/%2_settings.XXXXXX").arg(QDir::tempPath(), QCoreApplication::applicationName()); + g_tempConfigFile = new TemporaryFile(tmpFileName, qApp); + return g_tempConfigFile->fileName(); +} + TemporaryFile::TemporaryFile() : TemporaryFile(nullptr) { diff --git a/tests/util/TemporaryFile.h b/tests/util/TemporaryFile.h index 3c1cc6aa0..3f1707fda 100644 --- a/tests/util/TemporaryFile.h +++ b/tests/util/TemporaryFile.h @@ -34,6 +34,8 @@ public: using QFile::open; bool open(); bool copyFromFile(const QString& otherFileName); + + static QString createTempConfigFile(); }; #endif // KEEPASSXC_TEMPORARYFILE_H diff --git a/docs/FuzzTest.md b/utils/fuzz-testing/README.md similarity index 91% rename from docs/FuzzTest.md rename to utils/fuzz-testing/README.md index cb73fbd27..9f2c1fc27 100644 --- a/docs/FuzzTest.md +++ b/utils/fuzz-testing/README.md @@ -27,7 +27,7 @@ A special "instrumented build" is used that allows the fuzzer to look into the p $ CXX=afl-g++ AFL_HARDEN=1 cmake -DWITH_XC_ALL=ON .. $ make -In the source code, special behavior for fuzz testing can be implemented with `#ifdef __AFL_COMPILER`. For example, in fuzz builds, the KeePassXC CLI takes the database password from environment variable `KEYPASSXC_AFL_PASSWORD` to allow non-interactive operation. +In the source code, special behavior for fuzz testing can be implemented with `#ifdef __AFL_COMPILER`. For example, in fuzz builds, the KeePassXC CLI takes the database password from environment variable `KEEPASSXC_AFL_PASSWORD` to allow non-interactive operation. ## Prepare Fuzzer Input @@ -35,18 +35,18 @@ To get the fuzzer started, we provide empty password database files (the passwor $ cd buildafl $ mkdir -p findings/testcases - $ cp ../share/empty*.kdbx findings/testcases + $ cp ../utils/fuzz-testing/empty*.kdbx findings/testcases The fuzzer works by running KeePassXC with variations of this input, mutated in ways that make the program crash or hang. ## Run The Fuzzer $ cd buildafl - $ KEYPASSXC_AFL_PASSWORD=secret afl-fuzz -i findings/testcases -o findings -m 2000 -t 1000 src/cli/keepassxc-cli ls @@ + $ KEEPASSXC_AFL_PASSWORD=secret afl-fuzz -i findings/testcases -o findings -m 2000 -t 1000 src/cli/keepassxc-cli ls @@ This fuzz-tests the `ls` command of the KeePassXC CLI, which loads and decrypts a database file and then lists its contents. The parameters mean: -* `KEYPASSXC_AFL_PASSWORD=secret`: In fuzz test builds, the KeePassXC CLI takes the database password from this environment variable. +* `KEEPASSXC_AFL_PASSWORD=secret`: In fuzz test builds, the KeePassXC CLI takes the database password from this environment variable. * `-i findings/testcases`: The directory which contains the initial fuzzer input. * `-o findings`: The directory in which to store fuzzer results. * `-m 2000`: Fuzzer memory (in megabytes). Adjust as required if the fuzzer fails to start up. diff --git a/share/empty3.kdbx b/utils/fuzz-testing/empty3.kdbx similarity index 100% rename from share/empty3.kdbx rename to utils/fuzz-testing/empty3.kdbx diff --git a/share/empty4.kdbx b/utils/fuzz-testing/empty4.kdbx similarity index 100% rename from share/empty4.kdbx rename to utils/fuzz-testing/empty4.kdbx diff --git a/utils/keepassxc-cr-recovery/go.mod b/utils/keepassxc-cr-recovery/go.mod index 89afe5e32..7af231c05 100644 --- a/utils/keepassxc-cr-recovery/go.mod +++ b/utils/keepassxc-cr-recovery/go.mod @@ -2,4 +2,4 @@ module github.com/keepassxreboot/keepassxc/keepassxc-cr-recovery go 1.13 -require golang.org/x/crypto v0.0.0-20191227163750-53104e6ec876 +require golang.org/x/crypto v0.35.0 diff --git a/utils/keepassxc-cr-recovery/go.sum b/utils/keepassxc-cr-recovery/go.sum index 452e5b0ad..ed41f009f 100644 --- a/utils/keepassxc-cr-recovery/go.sum +++ b/utils/keepassxc-cr-recovery/go.sum @@ -1,8 +1,67 @@ +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20191227163750-53104e6ec876 h1:sKJQZMuxjOAR/Uo2LBfU90onWEf1dF4C+0hPJCc9Mpc= -golang.org/x/crypto v0.0.0-20191227163750-53104e6ec876/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc= +golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU= +golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8= +golang.org/x/crypto v0.35.0 h1:b15kiHdrGCHrP6LvwaQ3c03kgNhhiMgvlhxHQhmg2Xs= +golang.org/x/crypto v0.35.0/go.mod h1:dy7dXNW32cAb/6/PRuTNsix8T+vJAqvuIy5Bli/x0YQ= +golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= +golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/mod v0.15.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= +golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= +golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk= +golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44= +golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= +golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.11.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190412213103-97732733099d h1:+R4KGOnez64A81RvjARKc4UT5/tI9ujCIVX+P5KiHuI= -golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc= +golang.org/x/sys v0.30.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/telemetry v0.0.0-20240228155512-f48c80bd79b2/go.mod h1:TeRTkGYfJXctD9OcfyVLyj2J3IxLnKwHJR8f4D8a3YE= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= +golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= +golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU= +golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk= +golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY= +golang.org/x/term v0.29.0 h1:L6pJp37ocefwRRtYPKSWOWzOtWSxVajvz2ldH/xi3iU= +golang.org/x/term v0.29.0/go.mod h1:6bl4lRlvVuDgSf3179VpIxBF0o10JUpXWOnI7nErv7s= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= +golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= +golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= +golang.org/x/text v0.22.0/go.mod h1:YRoo4H8PVmsu+E3Ou7cqLVH8oXWIHVoX0jqUWALQhfY= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= +golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= +golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58= +golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= diff --git a/utils/keepassxc-kdewallet b/utils/keepassxc-kdewallet index 109183c5c..80623fe1a 100755 --- a/utils/keepassxc-kdewallet +++ b/utils/keepassxc-kdewallet @@ -9,14 +9,14 @@ KEEPASSXC=$(which -a keepassxc | sed -e "\\,$0,d" -e 'q') daemon_main() { # open kdewallet - handle=$(qdbus org.kde.kwalletd5 /modules/kwalletd5 org.kde.KWallet.open kdewallet 0 "$PROG") - while [[ true != $(qdbus org.kde.kwalletd5 /modules/kwalletd5 org.kde.KWallet.isOpen kdewallet) ]]; do + handle=$(qdbus6 org.kde.kwalletd6 /modules/kwalletd6 open kdewallet 0 "$PROG") + while [[ true != $(qdbus6 org.kde.kwalletd6 /modules/kwalletd6 isOpen kdewallet) ]]; do sleep 1 done declare -A DBs for DBPATH in $(ls -r $KDBX_SEARCH); do - DBs[$(realpath $DBPATH)]=$(qdbus org.kde.kwalletd5 /modules/kwalletd5 org.kde.KWallet.readPassword "$handle" "Passwords" "${DBPATH##*/}" "$PROG") + DBs[$(realpath $DBPATH)]=$(qdbus6 org.kde.kwalletd6 /modules/kwalletd6 readPassword "$handle" "Passwords" "${DBPATH##*/}" "$PROG") done # launch real keepassxc @@ -24,7 +24,7 @@ daemon_main() { "$KEEPASSXC" --pw-stdin "${!DBs[@]}" <<<"${DBs[*]}" & # done with kdewallet - qdbus org.kde.kwalletd5 /modules/kwalletd5 org.kde.KWallet.close "$handle" "false" "$PROG" + qdbus6 org.kde.kwalletd6 /modules/kwalletd6 close "$handle" "false" "$PROG" } if [[ $1 == '-d' ]]; then diff --git a/utils/keepassxc-snap-helper.sh b/utils/keepassxc-snap-helper.sh index 300b3909a..82b8acba1 100755 --- a/utils/keepassxc-snap-helper.sh +++ b/utils/keepassxc-snap-helper.sh @@ -94,6 +94,11 @@ setupEdge() { INSTALL_DIR="${BASE_DIR}/.config/microsoft-edge/NativeMessagingHosts" } +setupLibreWolf() { + JSON_OUT=${JSON_FIREFOX} + INSTALL_DIR="${BASE_DIR}/.librewolf/native-messaging-hosts" +} + # -------------------------------- # Start of script # -------------------------------- @@ -109,6 +114,7 @@ BROWSER=$(whiptail \ "5" "Brave" \ "6" "Tor Browser" \ "7" "Microsoft Edge" \ + "8" "LibreWolf" \ 3>&1 1>&2 2>&3) exitstatus=$? @@ -125,6 +131,7 @@ if [[ $exitstatus == 0 ]]; then 5) setupBrave ;; 6) setupTorBrowser ;; 7) setupEdge ;; + 8) setupLibreWolf ;; esac # Install the JSON file diff --git a/vcpkg-configuration.json b/vcpkg-configuration.json index 1d21b2694..b5a7fc340 100644 --- a/vcpkg-configuration.json +++ b/vcpkg-configuration.json @@ -1,5 +1,4 @@ { - "overlay-ports": [], "overlay-triplets": [ "vcpkg/triplets" ] diff --git a/vcpkg.json b/vcpkg.json index 0621736b0..8351862b4 100644 --- a/vcpkg.json +++ b/vcpkg.json @@ -1,7 +1,7 @@ { "name": "keepassxc", - "version-string": "2.7.7", - "builtin-baseline": "2a6371b01420d8820d158b4707e79931feba27aa", + "version-string": "2.8.0", + "builtin-baseline": "f9c128a6f7a96f5fa2f6f089f37ed6788a90e4b0", "dependencies": [ { "name": "argon2",