diff --git a/.gitignore b/.gitignore index 0521a42e3..479c589ea 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,6 @@ CMakeLists.txt.* build*/ +cmake-build-*/ release*/ .idea/ *.iml diff --git a/AppImage-Recipe.sh b/AppImage-Recipe.sh index 2707fe96b..c421aa79e 100755 --- a/AppImage-Recipe.sh +++ b/AppImage-Recipe.sh @@ -34,6 +34,7 @@ fi APP="$1" LOWERAPP="$(echo "$APP" | tr '[:upper:]' '[:lower:]')" VERSION="$2" +export ARCH=x86_64 mkdir -p $APP.AppDir wget -q https://github.com/probonopd/AppImages/raw/master/functions.sh -O ./functions.sh @@ -42,6 +43,8 @@ wget -q https://github.com/probonopd/AppImages/raw/master/functions.sh -O ./func LIB_DIR=./usr/lib if [ -d ./usr/lib/x86_64-linux-gnu ]; then LIB_DIR=./usr/lib/x86_64-linux-gnu +elif [ -d ./usr/lib64 ]; then + LIB_DIR=./usr/lib64 fi cd $APP.AppDir @@ -51,7 +54,7 @@ rm -R ./usr/local rmdir ./opt 2> /dev/null # bundle Qt platform plugins and themes -QXCB_PLUGIN="$(find /usr/lib -name 'libqxcb.so' 2> /dev/null)" +QXCB_PLUGIN="$(find /usr/lib* -name 'libqxcb.so' 2> /dev/null)" if [ "$QXCB_PLUGIN" == "" ]; then QXCB_PLUGIN="$(find /opt/qt*/plugins -name 'libqxcb.so' 2> /dev/null)" fi @@ -71,18 +74,22 @@ get_desktop get_icon cat << EOF > ./usr/bin/keepassxc_env #!/usr/bin/env bash -#export QT_QPA_PLATFORMTHEME=gtk2 export LD_LIBRARY_PATH="..$(dirname ${QT_PLUGIN_PATH})/lib:\${LD_LIBRARY_PATH}" -export QT_PLUGIN_PATH="..${QT_PLUGIN_PATH}" +export QT_PLUGIN_PATH="..${QT_PLUGIN_PATH}:\${KPXC_QT_PLUGIN_PATH}" # unset XDG_DATA_DIRS to make tray icon work in Ubuntu Unity -# see https://github.com/probonopd/AppImageKit/issues/351 +# see https://github.com/AppImage/AppImageKit/issues/351 unset XDG_DATA_DIRS -exec keepassxc "\$@" +if [ "\${1}" == "cli" ]; then + shift + exec keepassxc-cli "\$@" +else + exec keepassxc "\$@" +fi EOF chmod +x ./usr/bin/keepassxc_env -sed -i 's/Exec=keepassxc/Exec=keepassxc_env/' keepassxc.desktop +sed -i 's/Exec=keepassxc/Exec=keepassxc_env/' org.keepassxc.desktop get_desktopintegration $LOWERAPP GLIBC_NEEDED=$(glibc_needed) @@ -91,5 +98,5 @@ cd .. generate_type2_appimage -mv ../out/*.AppImage .. +mv ../out/*.AppImage ../KeePassXC-${VERSION}-${ARCH}.AppImage rmdir ../out > /dev/null 2>&1 diff --git a/CHANGELOG b/CHANGELOG index cc976c138..3719f8e4c 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,20 @@ +2.2.2 (2017-10-22) +========================= + +- Fixed entries with empty URLs being reported to KeePassHTTP clients [#1031] +- Fixed YubiKey detection and enabled CLI tool for AppImage binary [#1100] +- Added AppStream description [#1082] +- Improved TOTP compatibility and added new Base32 implementation [#1069] +- Fixed error handling when processing invalid cipher stream [#1099] +- Fixed double warning display when opening a database [#1037] +- Fixed unlocking databases with --pw-stdin [#1087] +- Added ability to override QT_PLUGIN_PATH environment variable for AppImages [#1079] +- Fixed transform seed not being regenerated when saving the database [#1068] +- Fixed only one YubiKey slot being polled [#1048] +- Corrected an issue with entry icons while merging [#1008] +- Corrected desktop and tray icons in Snap package [#1030] +- Fixed screen lock and Google fallback settings [#1029] + 2.2.1 (2017-10-01) ========================= diff --git a/CMakeLists.txt b/CMakeLists.txt index 976b32937..63281f93b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -49,9 +49,21 @@ set(CMAKE_AUTOUIC ON) set(KEEPASSXC_VERSION_MAJOR "2") set(KEEPASSXC_VERSION_MINOR "2") -set(KEEPASSXC_VERSION_PATCH "1") +set(KEEPASSXC_VERSION_PATCH "2") set(KEEPASSXC_VERSION "${KEEPASSXC_VERSION_MAJOR}.${KEEPASSXC_VERSION_MINOR}.${KEEPASSXC_VERSION_PATCH}") +# Distribution info +set(KEEPASSXC_DIST True) +set(KEEPASSXC_DIST_TYPE "Other" CACHE STRING "KeePassXC Distribution type") +set_property(CACHE KEEPASSXC_DIST_TYPE PROPERTY STRINGS Snap AppImage Other) +if(KEEPASSXC_DIST_TYPE STREQUAL "Snap") + set(KEEPASSXC_DIST_SNAP True) +elseif(KEEPASSXC_DIST_TYPE STREQUAL "AppImage") + set(KEEPASSXC_DIST_APPIMAGE True) +elseif(KEEPASSXC_DIST_TYPE STREQUAL "Other") + unset(KEEPASSXC_DIST) +endif() + if("${CMAKE_C_COMPILER}" MATCHES "clang$" OR "${CMAKE_C_COMPILER_ID}" STREQUAL "Clang") set(CMAKE_COMPILER_IS_CLANG 1) endif() diff --git a/COPYING b/COPYING index 481aaf726..403e4564b 100644 --- a/COPYING +++ b/COPYING @@ -214,10 +214,6 @@ Files: share/icons/database/C65_W.png Copyright: none License: public-domain -Files: src/crypto/salsa20/* -Copyright: none -License: public-domain - Files: src/streams/qtiocompressor.* src/streams/QtIOCompressor tests/modeltest.* @@ -241,8 +237,3 @@ Files: src/gui/KMessageWidget.h Copyright: 2011 Aurélien Gâteau 2014 Dominik Haumann License: LGPL-2.1 - -Files: src/totp/base32.cpp - src/totp/base32.h -Copyright: 2010 Google Inc. -License: Apache 2.0 \ No newline at end of file diff --git a/Dockerfile b/Dockerfile index 7da658219..6f7ace34c 100644 --- a/Dockerfile +++ b/Dockerfile @@ -14,49 +14,68 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see . -FROM ubuntu:14.04 +FROM centos:7 RUN set -x \ - && apt-get update \ - && apt-get install --yes software-properties-common + && curl "https://copr.fedorainfracloud.org/coprs/bugzy/keepassxc/repo/epel-7/bugzy-keepassxc-epel-7.repo" \ + > /etc/yum.repos.d/bugzy-keepassxc-epel-7.repo RUN set -x \ - && add-apt-repository ppa:george-edison55/cmake-3.x - -ENV QT_VERSION=qt59 + && curl "https://copr.fedorainfracloud.org/coprs/sic/backports/repo/epel-7/sic-backports-epel-7.repo" \ + > /etc/yum.repos.d/sic-backports-epel-7.repo RUN set -x \ - && add-apt-repository --yes ppa:beineri/opt-${QT_VERSION}-trusty - + && yum clean -y all \ + && yum upgrade -y +# build and runtime dependencies RUN set -x \ - && apt-get update \ - && apt-get install --yes \ - g++ \ + && yum install -y \ + make \ + automake \ + gcc-c++ \ cmake \ - libgcrypt20-dev \ - ${QT_VERSION}base \ - ${QT_VERSION}tools \ - ${QT_VERSION}x11extras \ - libxi-dev \ - libxtst-dev \ - zlib1g-dev \ - libyubikey-dev \ - libykpers-1-dev \ - xvfb \ - wget \ - file \ - fuse \ - python + libgcrypt16-devel \ + qt5-qtbase-devel \ + qt5-linguist \ + qt5-qttools \ + zlib-devel \ + qt5-qtx11extras \ + qt5-qtx11extras-devel \ + libXi-devel \ + libXtst-devel +# AppImage dependencies RUN set -x \ - && apt-get install --yes mesa-common-dev - + && yum install -y \ + wget \ + fuse-libs + +# build libyubikey +ENV YUBIKEY_VERSION=1.13 +RUN set -x && yum install -y libusb-devel +RUN set -x \ + && wget "https://developers.yubico.com/yubico-c/Releases/libyubikey-${YUBIKEY_VERSION}.tar.gz" \ + && tar xf libyubikey-${YUBIKEY_VERSION}.tar.gz \ + && cd libyubikey-${YUBIKEY_VERSION} \ + && ./configure --prefix=/usr --libdir=/usr/lib64 \ + && make \ + && make install \ + && cd .. \ + && rm -Rf libyubikey-${YUBIKEY_VERSION}* + +# build libykpers-1 +ENV YKPERS_VERSION=1.18.0 +RUN set -x \ + && wget "https://developers.yubico.com/yubikey-personalization/Releases/ykpers-${YKPERS_VERSION}.tar.gz" \ + && tar xf ykpers-${YKPERS_VERSION}.tar.gz \ + && cd ykpers-${YKPERS_VERSION} \ + && ./configure --prefix=/usr --libdir=/usr/lib64 \ + && make \ + && make install \ + && cd .. \ + && rm -Rf ykpers-${YKPERS_VERSION}* + VOLUME /keepassxc/src VOLUME /keepassxc/out WORKDIR /keepassxc - -ENV CMAKE_PREFIX_PATH=/opt/${QT_VERSION}/lib/cmake -ENV LD_LIBRARY_PATH=/opt/${QT_VERSION}/lib -RUN set -x \ - && echo /opt/${QT_VERSION}/lib > /etc/ld.so.conf.d/${QT_VERSION}.conf diff --git a/LICENSE.APACHE-2.0 b/LICENSE.APACHE-2.0 deleted file mode 100644 index 9c8f3ea08..000000000 --- a/LICENSE.APACHE-2.0 +++ /dev/null @@ -1,201 +0,0 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "{}" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright {yyyy} {name of copyright owner} - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. \ No newline at end of file diff --git a/README.md b/README.md index bf214d3c1..5588e3222 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,7 @@ KeePass Cross-platform Community Edition - Using website favicons as entry icons - Merging of databases - Automatic reload when the database changed on disk -- KeePassHTTP support for use with [PassIFox](https://addons.mozilla.org/en-us/firefox/addon/passifox/) in Mozilla Firefox and [chromeIPass](https://chrome.google.com/webstore/detail/chromeipass/ompiailgknfdndiefoaoiligalphfdae) in Google Chrome or Chromium, and [passafari](https://github.com/mmichaa/passafari.safariextension/) in Safari. +- KeePassHTTP support for use with KeePassHTTP-Connector for [Mozilla Firefox](https://addons.mozilla.org/en-US/firefox/addon/keepasshttp-connector/) and [Google Chrome or Chromium](https://chrome.google.com/webstore/detail/keepasshttp-connector/dafgdjggglmmknipkhngniifhplpcldb), and [passafari](https://github.com/mmichaa/passafari.safariextension/) in Safari. - Many bug fixes For a full list of features and changes, read the [CHANGELOG](CHANGELOG) document. diff --git a/release-tool b/release-tool index 680cdca2c..10c6a14c3 100755 --- a/release-tool +++ b/release-tool @@ -119,9 +119,11 @@ EOF Sign previously compiled release packages Options: - -f, --files Files to sign (required) - -g, --gpg-key GPG key used to sign the files (default: '${GPG_KEY}') - -h, --help Show this help + -f, --files Files to sign (required) + -g, --gpg-key GPG key used to sign the files (default: '${GPG_KEY}') + --signtool Specify the signtool executable (default: 'signtool') + --signtool-key Provide a key to be used with signtool (for Windows EXE) + -h, --help Show this help EOF fi } @@ -257,19 +259,18 @@ checkChangeLog() { grep -qPzo "${RELEASE_NAME} \(\d{4}-\d{2}-\d{2}\)\n=+\n" CHANGELOG if [ $? -ne 0 ]; then - exitError "CHANGELOG does not contain any information about the '${RELEASE_NAME}' release!" + exitError "'CHANGELOG' has not been updated to the '${RELEASE_NAME}' release!" fi } -checkTransifexCommandExists() { - command -v tx > /dev/null - if [ 0 -ne $? ]; then - exitError "Transifex tool 'tx' not installed! Please install it using 'pip install transifex-client'" +checkAppStreamInfo() { + if [ ! -f share/linux/org.keepassxc.appdata.xml ]; then + exitError "No AppStream info file found!" fi - command -v lupdate-qt5 > /dev/null - if [ 0 -ne $? ]; then - exitError "Qt Linguist tool (lupdate-qt5) is not installed! Please install using 'apt install qttools5-dev-tools'" + grep -qPzo "" share/linux/org.keepassxc.appdata.xml + if [ $? -ne 0 ]; then + exitError "'share/linux/org.keepassxc.appdata.xml' has not been updated to the '${RELEASE_NAME}' release!" fi } @@ -281,7 +282,24 @@ checkSnapcraft() { grep -qPzo "version: ${RELEASE_NAME}" snapcraft.yaml if [ $? -ne 0 ]; then - exitError "snapcraft.yaml has not been updated to the '${RELEASE_NAME}' release!" + exitError "'snapcraft.yaml' has not been updated to the '${RELEASE_NAME}' release!" + fi +} + +checkTransifexCommandExists() { + command -v tx > /dev/null + if [ 0 -ne $? ]; then + exitError "Transifex tool 'tx' not installed! Please install it using 'pip install transifex-client'" + fi +} + +checkQt5LUpdateExists() { + command -v lupdate > /dev/null + if [ 0 -eq $? ] && ! $(lupdate -version | grep -q "lupdate version 5\."); then + command -v lupdate-qt5 > /dev/null + if [ 0 -ne $? ]; then + exitError "Qt Linguist tool (lupdate-qt5) is not installed! Please install using 'apt install qttools5-dev-tools'" + fi fi } @@ -296,6 +314,7 @@ performChecks() { logInfo "Validating toolset and repository..." checkTransifexCommandExists + checkQt5LUpdateExists checkGitRepository checkReleaseDoesNotExist checkWorkingTreeClean @@ -309,6 +328,7 @@ performChecks() { checkVersionInCMake checkChangeLog + checkAppStreamInfo checkSnapcraft logInfo "\e[1m\e[32mAll checks passed!\e[0m" @@ -528,10 +548,10 @@ build() { checkWorkingTreeClean OUTPUT_DIR="$(realpath "$OUTPUT_DIR")" - + logInfo "Checking out release tag '${TAG_NAME}'..." git checkout "$TAG_NAME" - + logInfo "Creating output directory..." mkdir -p "$OUTPUT_DIR" @@ -598,7 +618,8 @@ build() { # Building on Linux without Docker container logInfo "Configuring build..." cmake -DCMAKE_BUILD_TYPE=Release -DWITH_TESTS=Off $CMAKE_OPTIONS \ - -DCMAKE_INSTALL_PREFIX="${INSTALL_PREFIX}" "$SRC_DIR" + -DCMAKE_INSTALL_PREFIX="${INSTALL_PREFIX}" \ + -DKEEPASSXC_DIST_TYPE=AppImage "$SRC_DIR" logInfo "Compiling sources..." make $MAKE_OPTIONS @@ -615,7 +636,7 @@ build() { logInfo "Launching Docker container to compile sources..." docker run --name "$DOCKER_CONTAINER_NAME" --rm \ - --cap-add SYS_ADMIN --device /dev/fuse \ + --cap-add SYS_ADMIN --security-opt apparmor:unconfined --device /dev/fuse \ -e "CC=${CC}" -e "CXX=${CXX}" \ -v "$(realpath "$SRC_DIR"):/keepassxc/src:ro" \ -v "$(realpath "$OUTPUT_DIR"):/keepassxc/out:rw" \ @@ -644,6 +665,8 @@ build() { # ----------------------------------------------------------------------- sign() { SIGN_FILES=() + SIGNTOOL="signtool" + SIGNTOOL_KEY="" while [ $# -ge 1 ]; do local arg="$1" @@ -657,6 +680,14 @@ sign() { -g|--gpg-key) GPG_KEY="$2" shift ;; + + --signtool) + SIGNTOOL="$2" + shift ;; + + --signtool-key) + SIGNTOOL_KEY="$2" + shift ;; -h|--help) printUsage "sign" @@ -675,13 +706,30 @@ sign() { printUsage "sign" exit 1 fi + + if [[ -n "$SIGNTOOL_KEY" && ! -f "$SIGNTOOL_KEY" ]]; then + exitError "Signtool Key was not found!" + elif [[ -f "$SIGNTOOL_KEY" && ! -x $(command -v "${SIGNTOOL}") ]]; then + exitError "signtool program not found on PATH!" + fi for f in "${SIGN_FILES[@]}"; do if [ ! -f "$f" ]; then exitError "File '${f}' does not exist!" fi + + if [[ -n "$SIGNTOOL_KEY" && ${f: -4} == '.exe' ]]; then + logInfo "Signing file '${f}' using signtool...\n" + read -s -p "Signtool Key Password: " password + echo + "${SIGNTOOL}" sign -f "${SIGNTOOL_KEY}" -p ${password} -v -t http://timestamp.comodoca.com/authenticode ${f} + + if [ 0 -ne $? ]; then + exitError "Signing failed!" + fi + fi - logInfo "Signing file '${f}'..." + logInfo "Signing file '${f}' using release key..." gpg --output "${f}.sig" --armor --local-user "$GPG_KEY" --detach-sig "$f" if [ 0 -ne $? ]; then diff --git a/share/CMakeLists.txt b/share/CMakeLists.txt index a609add79..6323ece88 100644 --- a/share/CMakeLists.txt +++ b/share/CMakeLists.txt @@ -30,7 +30,8 @@ if(UNIX AND NOT APPLE) install(DIRECTORY icons/application/ DESTINATION ${CMAKE_INSTALL_DATADIR}/icons/hicolor FILES_MATCHING PATTERN "application-x-keepassxc.png" PATTERN "application-x-keepassxc.svgz" PATTERN "status" EXCLUDE PATTERN "actions" EXCLUDE PATTERN "categories" EXCLUDE) - install(FILES linux/keepassxc.desktop DESTINATION ${CMAKE_INSTALL_DATADIR}/applications) + install(FILES linux/org.keepassxc.desktop DESTINATION ${CMAKE_INSTALL_DATADIR}/applications) + install(FILES linux/org.keepassxc.appdata.xml DESTINATION ${CMAKE_INSTALL_DATADIR}/metainfo) install(FILES linux/keepassxc.xml DESTINATION ${CMAKE_INSTALL_DATADIR}/mime/packages) endif(UNIX AND NOT APPLE) diff --git a/share/linux/keepassxc.xml b/share/linux/keepassxc.xml index 757047d2b..b26b4db25 100644 --- a/share/linux/keepassxc.xml +++ b/share/linux/keepassxc.xml @@ -1,7 +1,7 @@ - KeePass 2 database + KeePass 2 Database diff --git a/share/linux/org.keepassxc.appdata.xml b/share/linux/org.keepassxc.appdata.xml new file mode 100644 index 000000000..563450a4f --- /dev/null +++ b/share/linux/org.keepassxc.appdata.xml @@ -0,0 +1,218 @@ + + + + org.keepassxc + KeePassXC + CC-BY-3.0 + GPL-3.0+ + keepassxc + https://keepassxc.org + + application/x-keepass2 + + Community-driven port of the Windows application “KeePass Password Safe” + +

+ KeePassXC is an application for people with extremely high demands on secure + personal data management. It has a light interface, is cross-platform and + published under the terms of the GNU General Public License. +

+
+ + org.keepassxc.desktop + + + + https://keepassxc.org/images/screenshots/linux/screen_001.png + + + https://keepassxc.org/images/screenshots/linux/screen_002.png + + + https://keepassxc.org/images/screenshots/linux/screen_003.png + + + https://keepassxc.org/images/screenshots/linux/screen_004.png + + + https://keepassxc.org/images/screenshots/linux/screen_005.png + + + https://keepassxc.org/images/screenshots/linux/screen_006.png + + + https://keepassxc.org/images/screenshots/linux/screen_007.png + + + https://keepassxc.org/images/screenshots/linux/screen_008.png + + + https://keepassxc.org/images/screenshots/linux/screen_009.png + + + https://keepassxc.org/images/screenshots/linux/screen_010.png + + + https://keepassxc.org/images/screenshots/linux/screen_011.png + + + https://keepassxc.org/images/screenshots/linux/screen_012.png + + + https://keepassxc.org/images/screenshots/linux/screen_013.png + + + https://keepassxc.org/images/screenshots/linux/screen_014.png + + + + + + +
    +
  • Fixed entries with empty URLs being reported to KeePassHTTP clients [#1031]
  • +
  • Fixed YubiKey detection and enabled CLI tool for AppImage binary [#1100]
  • +
  • Added AppStream description [#1082]
  • +
  • Improved TOTP compatibility and added new Base32 implementation [#1069]
  • +
  • Fixed error handling when processing invalid cipher stream [#1099]
  • +
  • Fixed double warning display when opening a database [#1037]
  • +
  • Fixed unlocking databases with --pw-stdin [#1087]
  • +
  • Added ability to override QT_PLUGIN_PATH environment variable for AppImages [#1079]
  • +
  • Fixed transform seed not being regenerated when saving the database [#1068]
  • +
  • Fixed only one YubiKey slot being polled [#1048]
  • +
  • Corrected an issue with entry icons while merging [#1008]
  • +
  • Corrected desktop and tray icons in Snap package [#1030]
  • +
  • Fixed screen lock and Google fallback settings [#1029]
  • +
+
+
+ +
    +
  • Corrected multiple snap issues [#934, #1011]
  • +
  • Corrected multiple custom icon issues [#708, #719, #994]
  • +
  • Corrected multiple Yubikey issues [#880]
  • +
  • Fixed single instance preventing load on occasion [#997]
  • +
  • Keep entry history when merging databases [#970]
  • +
  • Prevent data loss if passwords were mismatched [#1007]
  • +
  • Fixed crash after merge [#941]
  • +
  • Added configurable auto-type default delay [#703]
  • +
  • Unlock database dialog window comes to front [#663]
  • +
  • Translation and compiling fixes
  • +
+
+
+ + +
    +
  • Added YubiKey 2FA integration for unlocking databases [#127]
  • +
  • Added TOTP support [#519]
  • +
  • Added CSV import tool [#146, #490]
  • +
  • Added KeePassXC CLI tool [#254]
  • +
  • Added diceware password generator [#373]
  • +
  • Added support for entry references [#370, #378]
  • +
  • Added support for Twofish encryption [#167]
  • +
  • Enabled DEP and ASLR for in-memory protection [#371]
  • +
  • Enabled single instance mode [#510]
  • +
  • Enabled portable mode [#645]
  • +
  • Enabled database lock on screensaver and session lock [#545]
  • +
  • Redesigned welcome screen with common features and recent databases [#292]
  • +
  • Multiple updates to search behavior [#168, #213, #374, #471, #603, #654]
  • +
  • Added auto-type fields {CLEARFIELD}, {SPACE}, {{}, {}} [#267, #427, #480]
  • +
  • Fixed auto-type errors on Linux [#550]
  • +
  • Prompt user prior to executing a cmd:// URL [#235]
  • +
  • Entry attributes can be protected (hidden) [#220]
  • +
  • Added extended ascii to password generator [#538]
  • +
  • Added new database icon to toolbar [#289]
  • +
  • Added context menu entry to empty recycle bin in databases [#520]
  • +
  • Added "apply" button to entry and group edit windows [#624]
  • +
  • Added macOS tray icon and enabled minimize on close [#583]
  • +
  • Fixed issues with unclean shutdowns [#170, #580]
  • +
  • Changed keyboard shortcut to create new database to CTRL+SHIFT+N [#515]
  • +
  • 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]
  • +
  • Added contributors list to about dialog [#629]
  • +
+
+
+ + +
    +
  • Bumped KeePassHTTP version to 1.8.4.2
  • +
  • KeePassHTTP confirmation window comes to foreground [#466]
  • +
+
+
+ + +
    +
  • Fix possible overflow in zxcvbn library [#363]
  • +
  • Revert HiDPI setting to avoid problems on laptop screens [#332]
  • +
  • Set file meta properties in Windows executable [#330]
  • +
  • Suppress error message when auto-reloading a locked database [#345]
  • +
  • Improve usability of question dialog when database is already locked by a different instance [#346]
  • +
  • Fix compiler warnings in QHttp library [#351]
  • +
  • Use unified toolbar on Mac OS X [#361]
  • +
  • Fix an issue on X11 where the main window would be raised instead of closed on Alt+F4 [#362]
  • +
+
+
+ + +
    +
  • Ask for save location when creating a new database [#302]
  • +
  • Remove Libmicrohttpd dependency to clean up the code and ensure better OS X compatibility [#317, #265]
  • +
  • Prevent Qt from degrading Wifi network performance on certain platforms [#318]
  • +
  • Visually refine user interface on OS X and other platforms [#299]
  • +
  • Remove unusable tray icon setting on OS X [#293]
  • +
  • Fix compositing glitches on Ubuntu and prevent flashing when minimizing to the tray at startup [#307]
  • +
  • Fix AppImage tray icon on Ubuntu [#277, #273]
  • +
  • Fix global menu disappearing after restoring KeePassXC from the tray on Ubuntu [#276]
  • +
  • Fix result order in entry search [#320]
  • +
  • Enable HiDPI scaling on supported platforms [#315]
  • +
  • Remove empty directories from installation target [#282]
  • +
+
+
+ + +
    +
  • Enabled HTTP plugin build; plugin is disabled by default and limited to localhost [#147]
  • +
  • Escape HTML in dialog boxes [#247]
  • +
  • Corrected crashes in favicon download and password generator [#233, #226]
  • +
  • Increase font size of password meter [#228]
  • +
  • Fixed compatibility with Qt 5.8 [#211]
  • +
  • Use consistent button heights in password generator [#229]
  • +
+
+
+ + +
    +
  • Show unlock dialog when using autotype on a closed database [#10, #89]
  • +
  • Show different tray icon when database is locked [#37, #46]
  • +
  • Support autotype on Windows and OS X [#42, #60, #63]
  • +
  • Add delay feature to autotype [#76, #77]
  • +
  • Add password strength meter [#84, #92]
  • +
  • Add option for automatically locking the database when minimizing the window [#57]
  • +
  • Add feature to download favicons and use them as entry icons [#30]
  • +
  • Automatically reload and merge database when the file changed on disk [#22, #33, #93]
  • +
  • Add tool for merging two databases [#22, #47, #143]
  • +
  • Add --pw-stdin commandline option to unlock the database by providing a password on STDIN [#54]
  • +
  • Add utility script for reading the database password from KWallet [#55]
  • +
  • Fix some KeePassHTTP settings not being remembered [#34, #65]
  • +
  • Make search box persistent [#15, #67, #157]
  • +
  • Enhance search feature by scoping the search to selected group [#16, #118]
  • +
  • Improve interaction between search field and entry list [#131, #141]
  • +
  • Add stand-alone password-generator [#18, #92]
  • +
  • Don't require password repetition when password is visible [#27, #92]
  • +
  • Add support for entry attributes in autotype sequences [#107]
  • +
  • Always focus password field when opening the database unlock widget [#116, #117]
  • +
  • Fix compilation errors on various platforms [#53, #126, #130]
  • +
  • Restructure and improve kdbx-extract utility [#160]
  • +
+
+
+
+
diff --git a/share/linux/keepassxc.desktop b/share/linux/org.keepassxc.desktop similarity index 62% rename from share/linux/keepassxc.desktop rename to share/linux/org.keepassxc.desktop index 1e72c4f84..d3b007bdc 100644 --- a/share/linux/keepassxc.desktop +++ b/share/linux/org.keepassxc.desktop @@ -1,13 +1,16 @@ [Desktop Entry] Name=KeePassXC -GenericName=Community Password Manager +GenericName=Password Manager GenericName[de]=Passwortverwaltung GenericName[es]=Gestor de contraseñas GenericName[fr]=Gestionnaire de mot de passe GenericName[ru]=менеджер паролей +Comment=Community-driven port of the Windows application “KeePass Password Safe” Exec=keepassxc %f +TryExec=keepassxc Icon=keepassxc Terminal=false Type=Application -Categories=Qt;Utility; +Version=1.0 +Categories=Utility;Security;Qt; MimeType=application/x-keepass2; diff --git a/share/translations/keepassx_cs.ts b/share/translations/keepassx_cs.ts index 6904b188e..737c2b03e 100644 --- a/share/translations/keepassx_cs.ts +++ b/share/translations/keepassx_cs.ts @@ -67,6 +67,10 @@ Jádro systému: %3 %4 Include the following information whenever you report a bug: K hlášení chyby vždy připojte následující údaje: + + Distribution: %1 + Distribuce: %1 + AccessControlDialog @@ -1095,7 +1099,7 @@ Chcete ji přesto otevřít? Custom icon already exists - + Tato vlastní ikona už existuje @@ -1318,6 +1322,17 @@ Můžete ho importovat pomocí Databáze → Importovat databázi ve formátu Ke Jedná se o jednosměrný převod. Databázi, vzniklou z importu, nepůjde otevřít ve staré verzi KeePassX 0.4. + + KeePass2Writer + + Unable to issue challenge-response. + Nedaří se vyvolat výzva-odpověď. + + + Unable to calculate master key + Nedaří se spočítat hlavní klíč + + Main @@ -1338,7 +1353,7 @@ Jedná se o jednosměrný převod. Databázi, vzniklou z importu, nepůjde otev Existing single-instance lock file is invalid. Launching new instance. - + Existující uzamykací soubor, zajišťující spuštění pouze jedné instance, není platný. Spouští se nová instance. diff --git a/share/translations/keepassx_da.ts b/share/translations/keepassx_da.ts index 55e91dd02..563f6adb3 100644 --- a/share/translations/keepassx_da.ts +++ b/share/translations/keepassx_da.ts @@ -67,6 +67,10 @@ Kerne: %3 %4 Include the following information whenever you report a bug: Inkludér følgende information når du indrapporterer en fejl: + + Distribution: %1 + + AccessControlDialog @@ -1313,6 +1317,17 @@ This is a one-way migration. You won't be able to open the imported databas + + KeePass2Writer + + Unable to issue challenge-response. + + + + Unable to calculate master key + Kan ikke beregne hovednøgle + + Main diff --git a/share/translations/keepassx_de.ts b/share/translations/keepassx_de.ts index 8c55f99ad..2fd20f04a 100644 --- a/share/translations/keepassx_de.ts +++ b/share/translations/keepassx_de.ts @@ -67,6 +67,10 @@ Kernel: %3 %4 Include the following information whenever you report a bug: Geben Sie folgende Informationen an, wenn Sie einen Bug melden: + + Distribution: %1 + Distribution: %1 + AccessControlDialog @@ -1092,7 +1096,7 @@ Möchten Sie diese dennoch öffnen? Custom icon already exists - + Es gibt bereits ein eigenes Symbol @@ -1315,6 +1319,17 @@ Zum Importieren gehen Sie auf Datenbank > 'KeePass 1-Datenbank importier Dieser Vorgang ist nur in eine Richtung möglich. Die importierte Datenbank kann später nicht mehr mit der alten KeePassX-Version 0.4 geöffnet werden. + + KeePass2Writer + + Unable to issue challenge-response. + Fehler beim Ausführen des Challenge-Response-Verfahrens + + + Unable to calculate master key + Berechnung des Hauptschlüssels gescheitert + + Main @@ -1335,7 +1350,7 @@ Dieser Vorgang ist nur in eine Richtung möglich. Die importierte Datenbank kann Existing single-instance lock file is invalid. Launching new instance. - + Vorhandene einmal-Sperrdatei ist ungültig. Starte neuen Vorgang. diff --git a/share/translations/keepassx_el.ts b/share/translations/keepassx_el.ts index a641c0d5e..5224c0242 100644 --- a/share/translations/keepassx_el.ts +++ b/share/translations/keepassx_el.ts @@ -67,6 +67,10 @@ Kernel: %3 %4 Include the following information whenever you report a bug: Συμπεριλάβετε τις ακόλουθες πληροφορίες όποτε αναφέρετε κάποιο σφάλμα: + + Distribution: %1 + + AccessControlDialog @@ -1311,6 +1315,17 @@ This is a one-way migration. You won't be able to open the imported databas + + KeePass2Writer + + Unable to issue challenge-response. + + + + Unable to calculate master key + Σε θέση να υπολογίσει το κύριο κλειδί + + Main diff --git a/share/translations/keepassx_en.ts b/share/translations/keepassx_en.ts index c971512ab..7cc9fc3c3 100644 --- a/share/translations/keepassx_en.ts +++ b/share/translations/keepassx_en.ts @@ -66,6 +66,10 @@ Kernel: %3 %4 Include the following information whenever you report a bug: + + Distribution: %1 + + AccessControlDialog @@ -1309,6 +1313,17 @@ This is a one-way migration. You won't be able to open the imported databas + + KeePass2Writer + + Unable to issue challenge-response. + + + + Unable to calculate master key + + + Main diff --git a/share/translations/keepassx_es.ts b/share/translations/keepassx_es.ts index 0fa7b14c6..f8176b807 100644 --- a/share/translations/keepassx_es.ts +++ b/share/translations/keepassx_es.ts @@ -67,6 +67,10 @@ Núcleo: %3 %4 Include the following information whenever you report a bug: Incluya la información siguiente cuando informe sobre un error: + + Distribution: %1 + + AccessControlDialog @@ -1317,6 +1321,17 @@ Puede importarla haciendo clic en Base de datos > 'Importar base de dato Esta migración es en único sentido. No podrá abrir la base de datos importada con la vieja versión 0.4 de KeePassX. + + KeePass2Writer + + Unable to issue challenge-response. + No se pudo hacer el desafío/respuesta: + + + Unable to calculate master key + No se puede calcular la clave maestra + + Main diff --git a/share/translations/keepassx_eu.ts b/share/translations/keepassx_eu.ts index 738dd29c5..ffbb4a9a5 100644 --- a/share/translations/keepassx_eu.ts +++ b/share/translations/keepassx_eu.ts @@ -65,6 +65,10 @@ Kernel: %3 %4 Include the following information whenever you report a bug: + + Distribution: %1 + + AccessControlDialog @@ -1300,6 +1304,17 @@ This is a one-way migration. You won't be able to open the imported databas + + KeePass2Writer + + Unable to issue challenge-response. + + + + Unable to calculate master key + Ezin izan da gako nagusia kalkulatu + + Main diff --git a/share/translations/keepassx_fi.ts b/share/translations/keepassx_fi.ts index 5f1862565..c7d61473e 100644 --- a/share/translations/keepassx_fi.ts +++ b/share/translations/keepassx_fi.ts @@ -67,6 +67,10 @@ Kernel: %3 %4 Include the following information whenever you report a bug: Sisällytä seuraavat tiedot aina kun ilmoitat ongelmasta: + + Distribution: %1 + + AccessControlDialog @@ -1314,6 +1318,17 @@ This is a one-way migration. You won't be able to open the imported databas + + KeePass2Writer + + Unable to issue challenge-response. + + + + Unable to calculate master key + Pääavaimen laskeminen ei onnistu + + Main diff --git a/share/translations/keepassx_fr.ts b/share/translations/keepassx_fr.ts index aa04ae5c0..90580e146 100644 --- a/share/translations/keepassx_fr.ts +++ b/share/translations/keepassx_fr.ts @@ -67,6 +67,10 @@ Kernel: %3 %4 Include the following information whenever you report a bug: Inclure l'information suivante lorsque vous signaler un bug: + + Distribution: %1 + + AccessControlDialog @@ -1318,6 +1322,17 @@ Vous pouvez l'importer en cliquant sur Base de données>'Importer u Il s'agit d'une migration à sens unique. Vous ne pourrez pas ouvrir la base de données importée avec l'ancienne version de KeePassX 0.4. + + KeePass2Writer + + Unable to issue challenge-response. + Impossible de lancer une challenge-réponse. + + + Unable to calculate master key + Impossible de calculer la clé maître + + Main diff --git a/share/translations/keepassx_hu.ts b/share/translations/keepassx_hu.ts index d4c2880f0..dc9877054 100644 --- a/share/translations/keepassx_hu.ts +++ b/share/translations/keepassx_hu.ts @@ -67,6 +67,10 @@ Kernel: %3 %4 Include the following information whenever you report a bug: Minden hibajelentésnél legyenek mellékelve ezek az információk: + + Distribution: %1 + Disztribúció: %1 + AccessControlDialog @@ -1094,7 +1098,7 @@ Mindenképp megnyitja? Custom icon already exists - + Az egyéni ikon már létezik @@ -1317,6 +1321,17 @@ Be lehet importálni az Adatbázis > „KeePass 1 adatbázis importálása… Ez egyirányú migráció. Nem lehet majd megnyitni az importált adatbázist a régi KeePassX 0.4 verzióval. + + KeePass2Writer + + Unable to issue challenge-response. + Nem lehet kiutalni a kihívás-választ. + + + Unable to calculate master key + Nem lehet kiszámítani a mesterkulcsot + + Main @@ -1337,7 +1352,7 @@ Ez egyirányú migráció. Nem lehet majd megnyitni az importált adatbázist a Existing single-instance lock file is invalid. Launching new instance. - + A meglévő egypéldányos zárolási fájl érvénytelen. Új példány indítása. diff --git a/share/translations/keepassx_id.ts b/share/translations/keepassx_id.ts index 8f7cd0232..f7db658d2 100644 --- a/share/translations/keepassx_id.ts +++ b/share/translations/keepassx_id.ts @@ -67,6 +67,10 @@ Kernel: %3 %4 Include the following information whenever you report a bug: Sertakan informasi berikut setiap Anda melaporkan bug: + + Distribution: %1 + + AccessControlDialog @@ -1317,6 +1321,17 @@ Anda bisa mengimpornya dengan mengklik Basis Data > 'Impor basis data Ke Ini adalah migrasi satu arah. Anda tidak akan bisa membuka basis data yang diimpor dengan versi lama KeePassX 0.4. + + KeePass2Writer + + Unable to issue challenge-response. + + + + Unable to calculate master key + Tidak bisa mengkalkulasi kunci utama + + Main diff --git a/share/translations/keepassx_it.ts b/share/translations/keepassx_it.ts index f60f0b264..5125a8b63 100644 --- a/share/translations/keepassx_it.ts +++ b/share/translations/keepassx_it.ts @@ -3,7 +3,7 @@ AboutDialog About KeePassXC - A proposito di KeePassXC + Info su KeePassXC About @@ -15,11 +15,11 @@ Debug Info - Informazioni di debug + Informazioni debug Copy to clipboard - Copia negli appunti + Copia negli Appunti Version %1 @@ -49,7 +49,7 @@ Kernel: %3 %4 Report bugs at: <a href="https://github.com/keepassxreboot/keepassxc/issues" style="text-decoration: underline;">https://github.com</a> - Segnala eventuali problemi su: <a href="https://github.com/keepassxreboot/keepassxc/issues" style="text-decoration: underline;">https://github.com</a> + Segnala eventuali problemi in: <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. @@ -57,7 +57,7 @@ Kernel: %3 %4 Project Maintainers: - Manutentori del progetto: + Manutenzione progetto: <a href="https://github.com/keepassxreboot/keepassxc/graphs/contributors">See Contributions on GitHub</a> @@ -65,7 +65,11 @@ Kernel: %3 %4 Include the following information whenever you report a bug: - Includi le seguenti informazioni quando segnali un problema: + Quando segnali un problema includi le seguenti informazioni: + + + Distribution: %1 + Distribuzione: %1 @@ -85,23 +89,23 @@ Kernel: %3 %4 %1 has requested access to passwords for the following item(s). Please select whether you want to allow access. - %1 ha richiesto accesso alle passwords per il seguente elemento(i). -Perfavore seleziona se vuoi consentire l'accesso. + %1 ha richiesto accesso alle passwords per il seguente elemento/i. +Seleziona se vuoi consentire l'accesso. KeePassXC HTTP Confirm Access - KeePassXC HTTP Conferma Accesso + KeePassXC HTTP conferma accesso AutoType Couldn't find an entry that matches the window title: - Impossibile trovare una voce che corrisponda al titolo della finestra + Impossibile trovare un elemento che corrisponda al titolo della finestra: Auto-Type - KeePassXC - Auto-Completamento - KeePassXC + Auto completamento - KeePassXC @@ -123,11 +127,11 @@ Perfavore seleziona se vuoi consentire l'accesso. AutoTypeSelectDialog Select entry to Auto-Type: - Seleziona una voce per Auto-Type: + Seleziona un elemento per l'auto completamento: Auto-Type - KeePassXC - Auto-Completamento - KeePassXC + KeePassXC - Auto completamento @@ -170,7 +174,7 @@ Perfavore seleziona se vuoi consentire l'accesso. Select a key file - Seleziona il file chiave + Seleziona un file chiave Do you really want to use an empty string as password? @@ -178,7 +182,7 @@ Perfavore seleziona se vuoi consentire l'accesso. Different passwords supplied. - Sono state fornite password differenti. + Sono state inserite password differenti. Failed to set %1 as the Key file: @@ -196,7 +200,7 @@ Perfavore seleziona se vuoi consentire l'accesso. Refresh - Ricarica + Aggiorna Empty password @@ -204,18 +208,18 @@ Perfavore seleziona se vuoi consentire l'accesso. Changing master key failed: no YubiKey inserted. - Cambio password principale fallito: nessuna YubiKey inserita. + Modifica password principale fallitoa. Nessuna YubiKey inserita. CloneDialog Clone Options - Opzioni di clonazione + Opzioni clonazione Replace username and password with references - Sostituisci nome user e password con riferimenti + Sostituisci nome utente e password con riferimenti Copy history @@ -238,7 +242,7 @@ Perfavore seleziona se vuoi consentire l'accesso. size, rows, columns - dimensione, righe. colonne + dimensione, righe, colonne Encoding @@ -262,11 +266,11 @@ Perfavore seleziona se vuoi consentire l'accesso. First record has field names - Il primo record ha i nomi dei campi + Il primo record contiene i nomi dei campi Number of headers line to discard - Numero di righe di intestazione da scartare + Numero righe di intestazione da scartare Consider '\' an escape character @@ -278,7 +282,7 @@ Perfavore seleziona se vuoi consentire l'accesso. Column layout - Disposizione di colonna + Disposizione colonna Not present in CSV file @@ -286,7 +290,7 @@ Perfavore seleziona se vuoi consentire l'accesso. Empty fieldname - Nome di campo vuoto + Nome campo vuoto column @@ -302,7 +306,7 @@ Perfavore seleziona se vuoi consentire l'accesso. Error(s) detected in CSV file ! - Errore(i) rilevati nel file CSV! + Errore/i rilevati nel file CSV! more messages skipped] @@ -315,7 +319,7 @@ Perfavore seleziona se vuoi consentire l'accesso. CSV import: writer has errors: - Importazione CSV: lo scrittore ha errori: + Importazione CSV: rilevati errori: @@ -323,7 +327,7 @@ Perfavore seleziona se vuoi consentire l'accesso. CsvImportWizard Import CSV file - Importare un file CSV + Importa file CSV Error @@ -389,7 +393,7 @@ Perfavore seleziona se vuoi consentire l'accesso. Refresh - Ricarica + Aggiorna Challenge Response: @@ -416,36 +420,36 @@ Perfavore seleziona se vuoi consentire l'accesso. Unable to open the database. - Impossibile aprire il database + Impossibile aprire il database. Success - Successo + Completato The database has been successfully repaired You can now save it. - Il database è stato riparato con successo + Il database è stato correttamente riparato. Adesso puoi salvarlo. Unable to repair the database. - Impossibile riparare il database + Impossibile riparare il database. DatabaseSettingsWidget Database name: - Nome del database: + Nome database: Database description: - Descrizione del database: + Descrizione database: Transform rounds: - Round di trasformazione: + Arrotondamenti trasformazione: Default username: @@ -453,23 +457,23 @@ Adesso puoi salvarlo. MiB - MiB + MB Benchmark - Prestazione + Prestazioni Max. history items: - Max. oggetti nella cronologia: + Oggetti max. nella cronologia: Max. history size: - Max. grandezza della cronologia: + Grandezza max. cronologia: Use recycle bin - Usa il cestino + Usa il Cestino AES: 256 Bit (default) @@ -488,7 +492,7 @@ Adesso puoi salvarlo. DatabaseTabWidget Root - Root + Radice KeePass 2 Database @@ -520,21 +524,21 @@ Adesso puoi salvarlo. Close? - Chiudere? + Vuoi chiudere? Save changes? - Salvare modifiche? + Vuoi salvare modifiche? "%1" was modified. Save changes? "%1" è stata modificato. -Salvare le modifiche? +Vuoi salvare le modifiche? Writing the database failed. - Scrittura del database non riuscita. + Scrittura del database fallita. Save database as @@ -556,7 +560,7 @@ Salvare le modifiche? Can't lock the database as you are currently editing it. Please press cancel to finish your changes or discard them. Non è possibile bloccare il database dato che lo stai modificando. -Premere Annulla per completare le modifiche o scartarle. +Seleziona 'Annulla' per completare le modifiche o scartarle. This database has never been saved. @@ -576,19 +580,19 @@ Altrimenti le modifiche verranno perse. "%1" is in edit mode. Discard changes and close anyway? "%1" è in modalità modifica. -Annullare le modifiche e chiudere comunque? +Vuoi annullare le modifiche e chiudere comunque? Export database to CSV file - Esporta il database come file CSV + Esporta database come file CSV CSV file - file CSV + File CSV Writing the CSV file failed. - Scrittura del file CSV non riuscita. + Scrittura file CSV fallita. Unable to open the database. @@ -610,18 +614,18 @@ Vuoi salvare comunque? Database already opened - Database già caricato + Database già aperto The database you are trying to open is locked by another instance of KeePassXC. Do you want to open it anyway? - Il database che stai provando ad aprire è bloccato da una altra instanza di KeePassXC. + Il database che stai cercando di aprire è bloccato da un'altra instanza di KeePassXC. Vuoi aprilo comunque? Open read-only - Aperto in sola lettura + Apri in sola lettura File opened in read only mode. @@ -629,42 +633,42 @@ Vuoi aprilo comunque? Open CSV file - Apri un file CSV + Apri file CSV DatabaseWidget Change master key - Cambia chiave principale + Modifica chiave principale Delete entry? - Eliminare voce? + Vuoi eliminare l'elemento? Do you really want to delete the entry "%1" for good? - Vuoi veramente eliminare la voce "%1"? + Vuoi veramente eliminare l'elemento "%1"? Delete entries? - Eliminare voci? + Vuoi eliminare gli elementi? Do you really want to delete %1 entries for good? - Vuoi veramente eliminare %1 voci? + Vuoi veramente eliminare %1 elementi? Move entries to recycle bin? - Muovere le voci nel cestino? + Vuoi spostare gli elementi nel Cestino? Do you really want to move %n entry(s) to the recycle bin? - Vuoi veramente spostare %n voce(i) nel cestino?Vuoi veramente spostare %n voce(i) nel cestino? + Vuoi veramente spostare %n elemento nel Cestino?Vuoi veramente spostare %n elementi nel Cestino? Delete group? - Eliminare gruppo? + Vuoi eliminare il gruppo? Do you really want to delete the group "%1" for good? @@ -676,23 +680,23 @@ Vuoi aprilo comunque? Move entry to recycle bin? - Muovere la voce nel cestino? + Vuoi spostare l'elemento nel Cestino? Do you really want to move entry "%1" to the recycle bin? - Vuoi veramente spostare la voce "%1" nel cestino? + Vuoi veramente spostare l'elemento "%1" nel Cestino? Searching... - Ricerca in corso... + Ricerca... No current database. - Nessun database corrente. + Nessun database attuale. No source database, nothing to do. - Nessun database sorgente, niente da fare. + Nessun database sorgente. Nessuna operazione da fare. Search Results (%1) @@ -704,11 +708,11 @@ Vuoi aprilo comunque? Execute command? - Esegui comando? + Vuoi eseguire il comando? Do you really want to execute the following command?<br><br>%1<br> - Sei sicuro di voler eseguire il comando seguente?<br><br>%1<br> + Sei sicuro di voler eseguire il seguente comando?<br><br>%1<br> Remember my choice @@ -716,19 +720,19 @@ Vuoi aprilo comunque? Autoreload Request - Auto ricarica le richieste + Ricaricamento automatico richieste The database file has changed. Do you want to load the changes? - Il file del database è cambiato. Vuoi caricare le modifiche? + Il file del database è stato modificato. Vuoi caricare le modifiche? Merge Request - Richiesta di fusione + Richiesta di unione The database file has changed and you have unsaved changes.Do you want to merge your changes? - Il file del database è cambiato e ci sono delle modifiche non salvate. Vuoi unire i tuoi cambiamenti. + Il file del database è stato modificato e ci sono delle modifiche non salvate. Vuoi unire i tuoi cambiamenti? Could not open the new database file while attempting to autoreload this database. @@ -736,18 +740,18 @@ Vuoi aprilo comunque? Empty recycle bin? - Svuotare il cestino? + Vuoi svuotare il Cestino? Are you sure you want to permanently delete everything from your recycle bin? - Sei sicuro di voler eliminare tutto definitivamente dal tuo Cestino? + Sei sicuro di voler eliminare tutto definitivamente dal Cestino? EditEntryWidget Entry - Voce + Elemento Advanced @@ -759,7 +763,7 @@ Vuoi aprilo comunque? Auto-Type - Auto-Type + Completamento automatico Properties @@ -771,19 +775,19 @@ Vuoi aprilo comunque? Entry history - Cronologia voce + Cronologia elemento Add entry - Aggiungere voce + Aggiungi elemento Edit entry - Modificare voce + Modifica elemento Different passwords supplied. - Sono state immesse password differenti. + Sono state inserite password differenti. New attribute @@ -799,7 +803,7 @@ Vuoi aprilo comunque? Save attachment - Salvare l'allegato + Salva allegato Unable to save the attachment: @@ -825,7 +829,7 @@ Vuoi aprilo comunque? Confirm Remove - Conferma l'eliminazione + Conferma eliminazione Are you sure you want to remove this attribute? @@ -833,7 +837,7 @@ Vuoi aprilo comunque? [PROTECTED] Press reveal to view or edit - [PROTETTO] Premere rivelare per visualizzare o modificare + [PROTETTO] Seleziona 'Rileva' per visualizzare o modificare Are you sure you want to remove this attachment? @@ -844,7 +848,7 @@ Vuoi aprilo comunque? EditEntryWidgetAdvanced Additional attributes - Attributi addizionali + Attributi aggiuntivi Add @@ -868,22 +872,22 @@ Vuoi aprilo comunque? Edit Name - Modifica il nome + Modifica nome Protect - Proteggere + Proteggi Reveal - Rivelare + Rivela EditEntryWidgetAutoType Enable Auto-Type for this entry - Abilita Auto-Type per questa voce + Abilita completamento automatico per questo elemento + @@ -899,11 +903,11 @@ Vuoi aprilo comunque? Inherit default Auto-Type sequence from the &group - Eredita la sequenza per l'Auto-Completamento dal &gruppo + Eredita la sequenza per il completamento automatico dal &gruppo &Use custom Auto-Type sequence: - &Usa sequenza di Auto-Completamento personalizzata: + &Usa sequenza di compeltamento automatico personalizzata: Use default se&quence @@ -915,14 +919,14 @@ Vuoi aprilo comunque? Window Associations - Associazioni di finestra + Associazioni finestra EditEntryWidgetHistory Show - Mostra + Visualizza Restore @@ -961,7 +965,7 @@ Vuoi aprilo comunque? Expires - Scade: + Scade Presets @@ -1027,15 +1031,15 @@ Vuoi aprilo comunque? Auto-Type - Auto-Type + Completamento automatico &Use default Auto-Type sequence of parent group - &Usa la sequenza di auto-digitazione predefinita del gruppo genitore + &Usa la sequenza di completamento automatico predefinita del gruppo genitore Set default Auto-Type se&quence - Imposta la se&quenza predefinita di auto-digitazione + Imposta se&quenza predefinita di completamento automatico @@ -1066,7 +1070,7 @@ Vuoi aprilo comunque? Unable to fetch favicon. - Impossibile scaricare la favicon. + Impossibile scaricare favicon. Can't read icon @@ -1082,19 +1086,19 @@ Vuoi aprilo comunque? Confirm Delete - Conferma la cancellazione + Conferma eliminazione This icon is used by %1 entries, and will be replaced by the default icon. Are you sure you want to delete it? - Questa icona viene utilizzata da %1 voci, e sarà sostituita dall'icona predefinita. Sei sicuro di volerla eliminare? + Questa icona viene usata da %1 elementi, e sarà sostituita dall'icona predefinita. Sei sicuro di volerla eliminare? Hint: You can enable Google as a fallback under Tools>Settings>Security - Suggerimento: è possibile abilitare Google come ripiego in Strumenti>Impostazioni>Sicurezza + Suggerimento: è possibile abilitare Google come alternativa in 'Strumenti'>'Impostazioni'>'Sicurezza' Custom icon already exists - + L'icona personalizzata esiste già @@ -1120,7 +1124,7 @@ Vuoi aprilo comunque? Entry - Clone - - Clona + - Clona @@ -1188,11 +1192,11 @@ Vuoi aprilo comunque? Character Types - Tipi di carattere + Tipi carattere Upper Case Letters - Lettere Maiuscole + Lettere maiuscole A-Z @@ -1200,7 +1204,7 @@ Vuoi aprilo comunque? Lower Case Letters - Lettere Minuscole + Lettere minuscole a-z @@ -1273,7 +1277,7 @@ Vuoi aprilo comunque? Root - Root + Radice Unable to calculate master key @@ -1313,8 +1317,19 @@ 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. Il file selezionato è un vecchio database di KeePass 1 (.kdb). -Puoi importarlo facendo clic su Database > 'Importa database KeePass 1...'. -Si tratta di una migrazione unidirezionale. Non sarai in grado di aprire il database importato con la vecchia versione di KeePassX 0.4. +È possibile importarlo facendo clic su 'Database' > 'Importa database KeePass 1...'. +Si tratta di una migrazione unidirezionale. Non sarà possibile aprire il database importato con la vecchia versione di KeePassX 0.4. + + + + KeePass2Writer + + Unable to issue challenge-response. + Non in grado dare la risposta di verifica. + + + Unable to calculate master key + Impossibile calcolare la chiave principale @@ -1333,11 +1348,11 @@ Si tratta di una migrazione unidirezionale. Non sarai in grado di aprire il data Another instance of KeePassXC is already running. - Un'altra istanza di KeePassXC è già in esecuzione. + È già in esecuzione un'altra istanza di KeePassXC. Existing single-instance lock file is invalid. Launching new instance. - + Il file di blocco singola istanza non è valido. Esegui una nuova istanza. @@ -1352,11 +1367,11 @@ Si tratta di una migrazione unidirezionale. Non sarai in grado di aprire il data Copy username to clipboard - Copia nome utente negli appunti + Copia nome utente negli Appunti Copy password to clipboard - Copia password negli appunti + Copia password negli Appunti Settings @@ -1364,7 +1379,7 @@ Si tratta di una migrazione unidirezionale. Non sarai in grado di aprire il data Show toolbar - Mostra barra degli strumenti + Visualizza barra strumenti read-only @@ -1372,7 +1387,7 @@ Si tratta di una migrazione unidirezionale. Non sarai in grado di aprire il data Toggle window - Cambia finestra + Abilita/disabilita finestra KeePass 2 Database @@ -1384,11 +1399,11 @@ Si tratta di una migrazione unidirezionale. Non sarai in grado di aprire il data Save repaired database - Salva il database riparato + Salva database riparato Writing the database failed. - Scrittura del database non riuscita. + Scrittura database fallita. &Recent databases @@ -1400,7 +1415,7 @@ Si tratta di una migrazione unidirezionale. Non sarai in grado di aprire il data Copy att&ribute to clipboard - Copia gli att&ributi nella clipboard + Copia gli att&ributi negli Appunti &Groups @@ -1440,7 +1455,7 @@ Si tratta di una migrazione unidirezionale. Non sarai in grado di aprire il data &View/Edit entry - &Vedi/Modifica l'elemento + &Visualizza/modifica elemento &Delete entry @@ -1460,7 +1475,7 @@ Si tratta di una migrazione unidirezionale. Non sarai in grado di aprire il data &Database settings - Impostazioni &Database + Impostazioni &database &Clone entry @@ -1496,7 +1511,7 @@ Si tratta di una migrazione unidirezionale. Non sarai in grado di aprire il data &Perform Auto-Type - &Esegui Auto-Completamento + &Esegui completamento automatico &Open URL @@ -1520,11 +1535,11 @@ Si tratta di una migrazione unidirezionale. Non sarai in grado di aprire il data Password Generator - Generatore Password + Genera password Clear history - Cancella cronologia + Azzera cronologia &Database @@ -1540,7 +1555,7 @@ Si tratta di una migrazione unidirezionale. Non sarai in grado di aprire il data Empty recycle bin - Svuota il cestino + Svuota il Cestino Access error for config file %1 @@ -1552,7 +1567,7 @@ Si tratta di una migrazione unidirezionale. Non sarai in grado di aprire il data Please touch the button on your YubiKey! - Prego tocca il pulsante sulla tua YubiKey! + Seleziona il pulsante nelal YubiKey! &Help @@ -1564,27 +1579,27 @@ Si tratta di una migrazione unidirezionale. Non sarai in grado di aprire il data Sa&ve database as... - Sal&va il database come... + Sal&va database come... Change &master key... - Ca&mbia la chiave principale... + &Modifica chiave principale... &Export to CSV file... - &Esporta su un file CSV... + &Esporta in file CSV... Import KeePass 1 database... - Importa un database di KeePass 1... + Importa database di KeePass 1... Import CSV file... - Importa un file CSV... + Importa file CSV... Re&pair database... - Ri&para il database... + Ri&para database... Set up TOTP... @@ -1595,7 +1610,7 @@ Si tratta di una migrazione unidirezionale. Non sarai in grado di aprire il data OptionDialog Dialog - Dialogo + Finestra General @@ -1603,15 +1618,15 @@ Si tratta di una migrazione unidirezionale. Non sarai in grado di aprire il data Sh&ow a notification when credentials are requested - M&ostra una notifica quando sono richeste le credenziali + Visualizza una n&otifica quando sono richeste le credenziali Sort matching entries by &username - Ordina le voci trovate per &nome utente + Ordina elementi trovati per &nome utente Re&move all stored permissions from entries in active database - R&imuovi tutti i permessi presenti dalle voci nel database attivo + R&imuovi tutti i permessi presenti negli elementi nel database attivo Advanced @@ -1619,15 +1634,15 @@ Si tratta di una migrazione unidirezionale. Non sarai in grado di aprire il data Always allow &access to entries - Permetti sempre di &accedere alle voci + Permetti sempre di &accedere agli elementi Always allow &updating entries - Permetti sempre di &aggiornare le voci + Permetti sempre di &aggiornare gli elementi Searc&h in all opened databases for matching entries - Cerc&a in tutti i database aperti per la ricerca delle voci + Cerc&a in tutti i database aperti gli elementi corrispondenti HTTP Port: @@ -1643,7 +1658,7 @@ Si tratta di una migrazione unidirezionale. Non sarai in grado di aprire il data Sort &matching entries by title - Ordina le voci per &titolo + Ordina gli elementi per &titolo KeePassXC will listen to this port on 127.0.0.1 @@ -1656,8 +1671,8 @@ Si tratta di una migrazione unidirezionale. Non sarai in grado di aprire il data Cannot bind to privileged ports below 1024! Using default port 19455. - Non è possibile collegarsi a porte sotto la 1024! -Utilizza la porta predefinita 19455. + Non è possibile usare porte sotto la 1024! +Usa la porta predefinita 19455. R&emove all shared encryption keys from active database @@ -1673,7 +1688,7 @@ Utilizza la porta predefinita 19455. This is required for accessing your databases from ChromeIPass or PassIFox - Questo è necessario per accedere ai tuoi database da ChromeIPass o PassIFox + Questo è necessario per accedere ai database da ChromeIPass o PassIFox Enable KeePassHTTP server @@ -1681,23 +1696,23 @@ Utilizza la porta predefinita 19455. Only returns the best matches for a specific URL instead of all entries for the whole domain. - Restituisce solo le corrispondenze migliori per un URL specifico invece di tutte le voci per l'intero dominio. + Restituisci solo le corrispondenze migliori per un'URL specifica invece di tutte gli elementi per l'intero dominio. &Return only best matching entries - &Restituisci solo le migliori voci corrispondenti + &Restituisci solo gli elementi corrispondenti migliori Only entries with the same scheme (http://, https://, ftp://, ...) are returned. - Solo le voci con lo stesso schema (http://, https://, ftp: //, ...) vengono restituite. + Solo gli elementi con lo stesso schema (http://, https://, ftp: //, ...) vengono restituite. &Match URL schemes - Co&mbina gli schemi URL + Sche&ma corrispndenza URL Password Generator - Generatore Password + Genera password Only the selected database has to be connected with a client. @@ -1718,7 +1733,7 @@ Modificale solo se sai quello che stai facendo. Character Types - Tipi di carattere + Tipi carattere Upper Case Letters @@ -1794,7 +1809,7 @@ Modificale solo se sai quello che stai facendo. Good - Sufficente + Buona Excellent @@ -1810,19 +1825,19 @@ Modificale solo se sai quello che stai facendo. Passphrase - Frase d'accesso + Frase accesso Wordlist: - Elenco di termini: + Elenco termini: Word Count: - Conteggio delle parole: + Conteggio parole: Word Separator: - Separatore delle parole: + Separatore parole: Copy @@ -1887,7 +1902,7 @@ Modificale solo se sai quello che stai facendo. YubiKey[%1] Challenge Response - Slot %2 - %3 - YubiKey [%1] Risposta di verifica - Slot %2 - %3 + YubiKey [%1] risposta di verifica - slot %2 - %3 Press @@ -1895,7 +1910,7 @@ Modificale solo se sai quello che stai facendo. Passive - Passivo + Passiva @@ -1936,7 +1951,7 @@ Modificale solo se sai quello che stai facendo. SearchWidget Case Sensitive - Case sensitive + Sensibile maiuscole/minuscole Search @@ -1944,7 +1959,7 @@ Modificale solo se sai quello che stai facendo. Clear - Pulisci + Azzera Search... @@ -1960,7 +1975,7 @@ Modificale solo se sai quello che stai facendo. A shared encryption-key with the name "%1" already exists. Do you want to overwrite it? - Una chiave di criptazione condivisa con il nome "%1" già esiste. + Una chiave di criptazione condivisa con il nome "%1" esiste già. Vuoi sovrascriverla? @@ -1971,11 +1986,11 @@ Vuoi sovrascriverla? The active database is locked! Please unlock the selected database or choose another one which is unlocked. Il database attivo è bloccato! -Sblocca il database selezionato o scegli un altro che è sbloccato +Sblocca il database selezionato o scegli un altro database sbloccato. Successfully removed %1 encryption-%2 from KeePassX/Http Settings. - Rimosso con successo %1 encryption-%2 dalle impostazioni KeePassX/Http. + Rimosso correttamente %1 encryption-%2 dalle impostazioni KeePassX/Http. No shared encryption-keys found in KeePassHttp Settings. @@ -1983,11 +1998,11 @@ Sblocca il database selezionato o scegli un altro che è sbloccato The active database does not contain an entry of KeePassHttp Settings. - Il database attivo non contiene nessuna voce delle impostazioni di KeePassHttp. + Il database attivo non contiene nessun elemento delle impostazioni di KeePassHttp. Removing stored permissions... - Rimuovi i permessi salvati... + Rimozione dei permessi salvati... Abort @@ -1995,11 +2010,11 @@ Sblocca il database selezionato o scegli un altro che è sbloccato Successfully removed permissions from %1 %2. - Permessi rimossi con successo da %1 %2. + Permessi rimossi correttamente da %1 %2. The active database does not contain an entry with permissions. - Il database attivo non contiene una voce con permessi. + Il database attivo non contiene un elemento con permessi. KeePassXC: New key association request @@ -2010,40 +2025,40 @@ Sblocca il database selezionato o scegli un altro che è sbloccato If you would like to allow it access to your KeePassXC database give it a unique name to identify and accept it. Hai ricevuto una richiesta di associazione per la chiave sovrastante. -Se vuoi permetterle di accedere al tuo database KeePassXC +Se vuoi permetterle di accedere al database KeePassXC imposta un nome unico per identificarla ed accettarla. KeePassXC: Overwrite existing key? - KeePassXC: Sovrascrivere chiave esistente? + KeePassXC- Vuoi sovrascrivere la chiave esistente? KeePassXC: Update Entry - KeePassXC: Aggiorna voce + KeePassXC- Aggiorna elemento KeePassXC: Database locked! - KeePassXC: Database bloccato! + KeePassXC- Database bloccato! KeePassXC: Removed keys from database - KeePassXC: Rimuovi chiavi dal database + KeePassXC - Chiavi rimosse dal database KeePassXC: No keys found - KeePassXC: Nessuna chiave trovata + KeePassXC - Nessuna chiave trovata KeePassXC: Settings not available! - KeePassXC: Impostazioni non disponibili! + KeePassXC - Impostazioni non disponibili! KeePassXC: Removed permissions - KeePassXC: Rimossi permessi + KeePassXC - Permessi rimossi KeePassXC: No entry with permissions found! - KeePassXC: Nessuna voce con permessi trovata! + KeePassXC - Nessun elemento con permessi trovata! @@ -2081,15 +2096,15 @@ imposta un nome unico per identificarla ed accettarla. Minimize when copying to clipboard - Minimizza quando si copia negli appunti + Minimizza quando si copia negli Appunti Use group icon on entry creation - Usa l'icona del gruppo alla creazione di una voce + Usa icona del gruppo alla creazione di un elemento Global Auto-Type shortcut - Scorciatoia Auto-Type globale + Scorciatoia completamento automatico globale Language @@ -2097,7 +2112,7 @@ imposta un nome unico per identificarla ed accettarla. Show a system tray icon - Mostra un'icona nell'area di notifica del sistema + Visualizza un'icona nell'area di notifica del sistema Hide window to system tray when minimized @@ -2105,7 +2120,7 @@ imposta un nome unico per identificarla ed accettarla. Load previous databases on startup - Carica i database precedenti all'avvio + All'avvio carica i database precedenti Automatically reload the database when modified externally @@ -2129,23 +2144,23 @@ imposta un nome unico per identificarla ed accettarla. Don't mark database as modified for non-data changes (e.g., expanding groups) - Non contrassegnare il database come modificato per modifiche non riguardanti i dati (ad es., espansione di gruppi) + Non contrassegnare il database come modificato per modifiche non riguardanti i dati (ad es. espansione dei gruppi) Auto-Type - Auto-Type + Completamento automatico Use entry title and URL to match windows for global Auto-Type - Usa il titolo della voce e l'URL per abbinare le finestre per l'auto-digitazione globale + Usa il titolo dell'elemento e l'URL per abbinare le finestre per il completamento automatico globale Always ask before performing Auto-Type - Chiedi sempre prima di effettuare l'auto-digitazione + Chiedi sempre prima di effettuare il completamento automatico Auto-Type delay - Ritardo dell'auto-digitazione + Ritardo completamento automatico ms @@ -2160,7 +2175,7 @@ imposta un nome unico per identificarla ed accettarla. SettingsWidgetSecurity Clear clipboard after - Pulisci appunti dopo + Svuota Appunti dopo sec @@ -2172,7 +2187,7 @@ imposta un nome unico per identificarla ed accettarla. Show passwords in cleartext by default - Mostra la password in chiaro in maniera predefinita + Visualizza la password in chiaro in maniera predefinita Lock databases after minimizing the window @@ -2192,7 +2207,7 @@ imposta un nome unico per identificarla ed accettarla. Lock databases when session is locked or lid is closed - Bloccare i database quando la sessione è bloccata o il coperchio è chiuso + Blocca i database quando la sessione è bloccata o il coperchio è chiuso Privacy @@ -2200,7 +2215,7 @@ imposta un nome unico per identificarla ed accettarla. Use Google as fallback for downloading website icons - Utilizza Google come ripiego per scaricare le icone del sito web + Usa Google come alternativa per scaricare le icone dal sito web @@ -2215,11 +2230,11 @@ imposta un nome unico per identificarla ed accettarla. Use custom settings - Utilizza le impostazioni personalizzate + Usa le impostazioni personalizzate Note: Change these settings only if you know what you are doing. - Nota: modificare queste impostazioni solo se sai quello che stai facendo. + Nota: modifica queste impostazioni solo se sai quello che stai facendo. Time step: @@ -2235,7 +2250,7 @@ imposta un nome unico per identificarla ed accettarla. Code size: - Dimensioni del codice: + Dimensioni codice: sec @@ -2258,7 +2273,7 @@ imposta un nome unico per identificarla ed accettarla. Expires in - Scade in + Scade tra seconds @@ -2315,7 +2330,7 @@ imposta un nome unico per identificarla ed accettarla. KeePassXC - cross-platform password manager - KeePassXC - gestore password multipiattaforma + KeePassXC - Gestore password multipiattaforma read password of the database from stdin @@ -2335,11 +2350,11 @@ imposta un nome unico per identificarla ed accettarla. Use a GUI prompt unlocking the database. - Utilizza un sollecito grafico per lo sblocco del database. + Usa una richiesta grafica per lo sblocco del database. Name of the entry to clip. - Nome della voce da troncare. + Nome dell'elemento da tagliare. Extract and print the content of a database. @@ -2355,7 +2370,7 @@ imposta un nome unico per identificarla ed accettarla. List database entries. - Elenco delle voci del database. + Elenco degli elementi del database. Path of the group to list. Default is / @@ -2363,7 +2378,7 @@ imposta un nome unico per identificarla ed accettarla. Print the UUIDs of the entries and groups. - Stampa gli UUID delle voci e dei gruppi. + Stampa gli UUID degli elementi e dei gruppi. Merge two databases. @@ -2371,15 +2386,15 @@ imposta un nome unico per identificarla ed accettarla. Path of the database to merge into. - Percorso del database di destinazione da unire + Percorso del database destinazione da unire. Path of the database to merge from. - Percorso del database di partenza da unire. + Percorso del database sorgente da unire. Use the same password for both database files. - Utilizza la stessa password per entrambi i file di database. + Usa la stessa password per entrambi i file dei database. Show a password. @@ -2387,7 +2402,7 @@ imposta un nome unico per identificarla ed accettarla. Name of the entry to show. - Nome della voce da mostrare. + Nome dell'elemento da visualizzare. \ No newline at end of file diff --git a/share/translations/keepassx_ja.ts b/share/translations/keepassx_ja.ts index 4ac8b7ee7..28b7c5336 100644 --- a/share/translations/keepassx_ja.ts +++ b/share/translations/keepassx_ja.ts @@ -67,6 +67,10 @@ CPU アーキテクチャ: %2 Include the following information whenever you report a bug: バグを報告する際に下記の情報を含めてください: + + Distribution: %1 + + AccessControlDialog @@ -1094,7 +1098,7 @@ Do you want to open it anyway? Custom icon already exists - + カスタムアイコンは既に存在します @@ -1317,6 +1321,17 @@ This is a one-way migration. You won't be able to open the imported databas これは一方向の移行操作であり、インポートされたデータベースは古い KeePassX 0.4 のバージョンでは開くことはできません。 + + KeePass2Writer + + Unable to issue challenge-response. + チャレンジレスポンスを発行することができません。 + + + Unable to calculate master key + マスターキーを計算できません + + Main @@ -1337,7 +1352,7 @@ This is a one-way migration. You won't be able to open the imported databas Existing single-instance lock file is invalid. Launching new instance. - + 既存のシングルインスタンスロックファイルは無効です。新しいインスタンスを起動します。 diff --git a/share/translations/keepassx_kk.ts b/share/translations/keepassx_kk.ts index 073052717..4531122bf 100644 --- a/share/translations/keepassx_kk.ts +++ b/share/translations/keepassx_kk.ts @@ -64,6 +64,10 @@ Kernel: %3 %4 Include the following information whenever you report a bug: + + Distribution: %1 + + AccessControlDialog @@ -1307,6 +1311,17 @@ This is a one-way migration. You won't be able to open the imported databas + + KeePass2Writer + + Unable to issue challenge-response. + + + + Unable to calculate master key + Басты парольді есептеу мүмкін емес + + Main diff --git a/share/translations/keepassx_ko.ts b/share/translations/keepassx_ko.ts index ff6c208b8..0b528474d 100644 --- a/share/translations/keepassx_ko.ts +++ b/share/translations/keepassx_ko.ts @@ -67,6 +67,10 @@ CPU 아키텍처: %2 Include the following information whenever you report a bug: 버그를 보고할 때 다음 정보를 포함하십시오: + + Distribution: %1 + + AccessControlDialog @@ -1315,6 +1319,17 @@ This is a one-way migration. You won't be able to open the imported databas 이 작업은 한 방향으로만 이뤄집니다. 가져온 데이터베이스는 KeePassX 0.4 버전에서 열 수 없습니다. + + KeePass2Writer + + Unable to issue challenge-response. + 질의 응답을 실행할 수 없습니다. + + + Unable to calculate master key + 마스터 키를 계산할 수 없습니다 + + Main diff --git a/share/translations/keepassx_lt.ts b/share/translations/keepassx_lt.ts index be7a82e09..a9a483836 100644 --- a/share/translations/keepassx_lt.ts +++ b/share/translations/keepassx_lt.ts @@ -67,6 +67,10 @@ Branduolys: %3 %4 Include the following information whenever you report a bug: Pranešdami apie klaidą, visuomet pateikite ir šią informaciją: + + Distribution: %1 + Platinimas: %1 + AccessControlDialog @@ -1094,7 +1098,7 @@ Ar vis tiek norite ją atverti? Custom icon already exists - + Tinkinta piktograma jau yra @@ -1317,6 +1321,17 @@ Jūs galite ją importuoti, nuspausdami Duomenų bazė > "Importuoti Kee Tai yra vienakryptis perkėlimas. Jūs negalėsite atverti importuotos duomenų bazės, naudodami senąją KeePassX 0.4 versija. + + KeePass2Writer + + Unable to issue challenge-response. + Nepavyko išduoti iššūkio atsakymo. + + + Unable to calculate master key + Nepavyko apskaičiuoti pagrindinio rakto + + Main @@ -1337,7 +1352,7 @@ Tai yra vienakryptis perkėlimas. Jūs negalėsite atverti importuotos duomenų Existing single-instance lock file is invalid. Launching new instance. - + Esamas vieno egzemplioriaus užrakto failas yra neteisingas. Paleidžiamas naujas egzempliorius. diff --git a/share/translations/keepassx_nl_NL.ts b/share/translations/keepassx_nl_NL.ts index c8fd30dd6..e18f1a908 100644 --- a/share/translations/keepassx_nl_NL.ts +++ b/share/translations/keepassx_nl_NL.ts @@ -64,6 +64,10 @@ Kernel: %3 %4 Include the following information whenever you report a bug: + + Distribution: %1 + + AccessControlDialog @@ -1310,6 +1314,17 @@ This is a one-way migration. You won't be able to open the imported databas + + KeePass2Writer + + Unable to issue challenge-response. + + + + Unable to calculate master key + Niet mogelijk om hoofdsleutel te berekenen + + Main diff --git a/share/translations/keepassx_pl.ts b/share/translations/keepassx_pl.ts index 1ed4ed058..66574202f 100644 --- a/share/translations/keepassx_pl.ts +++ b/share/translations/keepassx_pl.ts @@ -67,6 +67,10 @@ Jądro: %3 %4 Include the following information whenever you report a bug: Uwzględnij następujące informacje, gdy zgłaszasz błąd: + + Distribution: %1 + Dystrybucja: %1 + AccessControlDialog @@ -1095,7 +1099,7 @@ Czy chcesz ją otworzyć mimo to? Custom icon already exists - + Ikona niestandardowa już istnieje @@ -1318,6 +1322,17 @@ Możesz zaimportować ją przez wybranie Baza danych > 'Importuj bazę d Jest to migracja w jedną stronę. Nie będzie można otworzyć importowanej bazy danych za pomocą starej wersji KeePassX 0.4. + + KeePass2Writer + + Unable to issue challenge-response. + Nie można wywołać wyzwania-odpowiedzi. + + + Unable to calculate master key + Nie mogę wyliczyć głównego klucza + + Main @@ -1338,7 +1353,7 @@ Jest to migracja w jedną stronę. Nie będzie można otworzyć importowanej baz Existing single-instance lock file is invalid. Launching new instance. - + Istniejący plik blokady pojedynczego wystąpienia jest nieprawidłowy. Uruchamianie nowego wystąpienia. diff --git a/share/translations/keepassx_pt_BR.ts b/share/translations/keepassx_pt_BR.ts index b4f792605..1ea54d854 100644 --- a/share/translations/keepassx_pt_BR.ts +++ b/share/translations/keepassx_pt_BR.ts @@ -67,6 +67,10 @@ Kernel: %3 %4 Include the following information whenever you report a bug: Inclua as informações abaixo quando reportar um erro: + + Distribution: %1 + + AccessControlDialog @@ -1314,6 +1318,17 @@ This is a one-way migration. You won't be able to open the imported databas + + KeePass2Writer + + Unable to issue challenge-response. + + + + Unable to calculate master key + Não foi possível calcular a chave mestre + + Main diff --git a/share/translations/keepassx_pt_PT.ts b/share/translations/keepassx_pt_PT.ts index cf9f124fe..0a671ed70 100644 --- a/share/translations/keepassx_pt_PT.ts +++ b/share/translations/keepassx_pt_PT.ts @@ -67,6 +67,10 @@ Kernel: %3 %4 Include the following information whenever you report a bug: Inclua as seguintes informações sempre que reportar um erro: + + Distribution: %1 + Distribuição: %1 + AccessControlDialog @@ -1095,7 +1099,7 @@ Ainda assim deseja abrir a base de dados? Custom icon already exists - + Já existe um ícone personalizado @@ -1318,6 +1322,17 @@ Pode importá-lo clicando em Base de dados - > 'Importar base de dados d Esta é uma migração unidirecional. Não será possível abrir a base de dados importada com a versão 0.4 do KeePassX. + + KeePass2Writer + + Unable to issue challenge-response. + Incapaz de emitir a pergunta de segurança. + + + Unable to calculate master key + Impossível de calcular a chave-mestre + + Main @@ -1338,7 +1353,7 @@ Esta é uma migração unidirecional. Não será possível abrir a base de dados Existing single-instance lock file is invalid. Launching new instance. - + O ficheiro de bloqueio da instância única é inválido. A iniciar nova instância. diff --git a/share/translations/keepassx_ru.ts b/share/translations/keepassx_ru.ts index c206b769f..938d5eefd 100644 --- a/share/translations/keepassx_ru.ts +++ b/share/translations/keepassx_ru.ts @@ -67,6 +67,10 @@ Kernel: %3 %4 Include the following information whenever you report a bug: Включите следующую информацию, когда сообщаете об ошибке: + + Distribution: %1 + + AccessControlDialog @@ -1318,6 +1322,17 @@ This is a one-way migration. You won't be able to open the imported databas Это одностороннее перемещение. Вы не сможете открыть импортированную базу данных на старой версии KeePassX 0,4. + + KeePass2Writer + + Unable to issue challenge-response. + Не удалось выполнить запрос ответа. + + + Unable to calculate master key + Невозможно вычислить мастер-пароль + + Main diff --git a/share/translations/keepassx_sl_SI.ts b/share/translations/keepassx_sl_SI.ts index f43dd17ab..cec9bd6ca 100644 --- a/share/translations/keepassx_sl_SI.ts +++ b/share/translations/keepassx_sl_SI.ts @@ -64,6 +64,10 @@ Kernel: %3 %4 Include the following information whenever you report a bug: + + Distribution: %1 + + AccessControlDialog @@ -1305,6 +1309,17 @@ This is a one-way migration. You won't be able to open the imported databas + + KeePass2Writer + + Unable to issue challenge-response. + + + + Unable to calculate master key + Izračun glavnega ključa ni uspel + + Main diff --git a/share/translations/keepassx_sv.ts b/share/translations/keepassx_sv.ts index bc846e46c..a9e8a85d7 100644 --- a/share/translations/keepassx_sv.ts +++ b/share/translations/keepassx_sv.ts @@ -24,7 +24,8 @@ Version %1 - + Version %1 + Revision: %1 @@ -64,6 +65,10 @@ Kernel: %3 %4 Include the following information whenever you report a bug: + + Distribution: %1 + + AccessControlDialog @@ -196,7 +201,7 @@ Please select whether you want to allow access. Empty password - + Tomt lösenord Changing master key failed: no YubiKey inserted. @@ -254,7 +259,7 @@ Please select whether you want to allow access. Comments start with - + Kommentarer inleds med First record has field names @@ -282,7 +287,7 @@ Please select whether you want to allow access. Empty fieldname - + Tomt fältnamn column @@ -337,7 +342,7 @@ Please select whether you want to allow access. rows, - + rader, columns @@ -622,7 +627,7 @@ Do you want to open it anyway? Open CSV file - + Öppna CSV fil @@ -677,7 +682,7 @@ Do you want to open it anyway? Searching... - + Söker... No current database. @@ -689,11 +694,11 @@ Do you want to open it anyway? Search Results (%1) - + Sökresultat (%1) No Results - + Inget resultat Execute command? @@ -818,7 +823,7 @@ Do you want to open it anyway? Confirm Remove - + Bekräfta borttagning Are you sure you want to remove this attribute? @@ -865,7 +870,7 @@ Do you want to open it anyway? Protect - + Skydda Reveal @@ -1307,6 +1312,17 @@ This is a one-way migration. You won't be able to open the imported databas + + KeePass2Writer + + Unable to issue challenge-response. + + + + Unable to calculate master key + Kunde inte räkna nu master-nyckeln + + Main diff --git a/share/translations/keepassx_tr.ts b/share/translations/keepassx_tr.ts index 18639fc48..4514a4204 100644 --- a/share/translations/keepassx_tr.ts +++ b/share/translations/keepassx_tr.ts @@ -67,6 +67,10 @@ MİB mimarisi: %2 Include the following information whenever you report a bug: Bir hata bildirirken şu bilgileri ekleyin: + + Distribution: %1 + + AccessControlDialog @@ -1313,6 +1317,17 @@ Veri tabanı > 'KeePass1 veri tabanı içe aktar...'a tıklayarak i Bu tek yönlü bir yer değiştirmedir. İçe aktarılan veri tabanını eski KeePassX 0.4 sürümüyle açamayacaksınız. + + KeePass2Writer + + Unable to issue challenge-response. + + + + Unable to calculate master key + Ana anahtar hesaplanamıyor + + Main diff --git a/share/translations/keepassx_uk.ts b/share/translations/keepassx_uk.ts index e1f98f86a..c8abb87fb 100644 --- a/share/translations/keepassx_uk.ts +++ b/share/translations/keepassx_uk.ts @@ -67,6 +67,10 @@ Kernel: %3 %4 Include the following information whenever you report a bug: Коли Ви повідомляєте про ваду, завжди долучайте таку інформацію: + + Distribution: %1 + + AccessControlDialog @@ -1318,6 +1322,17 @@ This is a one-way migration. You won't be able to open the imported databas Перетворення можливе лише в одному напрямку. Ви не зможете відкрити імпортоване сховище старою версією KeePassX 0.4. + + KeePass2Writer + + Unable to issue challenge-response. + Неможливо видати виклик-відповідь. + + + Unable to calculate master key + Неможливо вирахувати головний ключ + + Main diff --git a/share/translations/keepassx_zh_CN.ts b/share/translations/keepassx_zh_CN.ts index db791625a..0d5e2806f 100644 --- a/share/translations/keepassx_zh_CN.ts +++ b/share/translations/keepassx_zh_CN.ts @@ -67,6 +67,10 @@ CPU 架构:%2 Include the following information whenever you report a bug: 报告任何 bug 时,请包含以下信息: + + Distribution: %1 + + AccessControlDialog @@ -1316,6 +1320,17 @@ This is a one-way migration. You won't be able to open the imported databas 这是不可逆的迁移,导入后的数据库将无法由旧版本的 KeePassX 0.4 打开。 + + KeePass2Writer + + Unable to issue challenge-response. + 无法发出挑战应答 + + + Unable to calculate master key + 无法计算主密码 + + Main diff --git a/share/translations/keepassx_zh_TW.ts b/share/translations/keepassx_zh_TW.ts index af9c74b55..0dbabb3ab 100644 --- a/share/translations/keepassx_zh_TW.ts +++ b/share/translations/keepassx_zh_TW.ts @@ -67,6 +67,10 @@ Kernel: %3 %4 Include the following information whenever you report a bug: 回報 Bug 時會包含以下資訊: + + Distribution: %1 + + AccessControlDialog @@ -1317,6 +1321,17 @@ This is a one-way migration. You won't be able to open the imported databas 這是單向遷移。你無法用舊的 KeePassX 0.4 的版本開啟已匯入的資料庫。 + + KeePass2Writer + + Unable to issue challenge-response. + + + + Unable to calculate master key + 無法計算主金鑰 + + Main diff --git a/snapcraft.yaml b/snapcraft.yaml index edd2cf227..0d69941ac 100644 --- a/snapcraft.yaml +++ b/snapcraft.yaml @@ -1,18 +1,18 @@ name: keepassxc -version: 2.2.1 +version: 2.2.2 grade: stable -summary: community driven port of the windows application “Keepass Password Safe” +summary: Community-driven port of the Windows application “KeePass Password Safe” description: | KeePassXC is an application for people with extremely high demands on secure - personal data management. It has a light interface, is cross platform and - is published under the terms of the GNU General Public License. + personal data management. It has a light interface, is cross-platform and + published under the terms of the GNU General Public License. confinement: strict apps: keepassxc: command: desktop-launch keepassxc plugs: [unity7, x11, opengl, gsettings, home, network, network-bind, removable-media, raw-usb] - desktop: share/applications/keepassxc.desktop + desktop: usr/share/applications/org.keepassxc.desktop cli: command: keepassxc-cli plugs: [gsettings, home, removable-media, raw-usb] @@ -23,6 +23,8 @@ parts: plugin: cmake configflags: - -DCMAKE_BUILD_TYPE=Release + - -DCMAKE_INSTALL_PREFIX=/usr + - -DKEEPASSXC_DIST_TYPE=Snap - -DWITH_TESTS=OFF - -DWITH_XC_AUTOTYPE=ON - -DWITH_XC_HTTP=ON @@ -39,6 +41,8 @@ parts: - libxtst-dev - libyubikey-dev - libykpers-1-dev + install: | + sed -i 's|Icon=keepassxc|Icon=${SNAP}/usr/share/icons/hicolor/256x256/apps/keepassxc.png|g' $SNAPCRAFT_PART_INSTALL/usr/share/applications/org.keepassxc.desktop after: [desktop-qt5] # Redefine desktop-qt5 stage packages to work with Ubuntu 17.04 @@ -55,10 +59,12 @@ parts: - locales-all # Overcome limitation in snapd to support URL loading (CTRL+U) + # client needs to install "snapd-xdg-open" on their system snapd-xdg-open: source: https://github.com/ubuntu-core/snapd-xdg-open.git - plugin: dump - organize: - data/xdg-open: bin/xdg-open + source-depth: 1 + plugin: nil + install: | + install -D -t $SNAPCRAFT_PART_INSTALL/usr/bin/ data/xdg-open stage-packages: - dbus diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 791685576..5255186ea 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -59,6 +59,8 @@ set(keepassx_SOURCES core/Tools.cpp core/Translator.cpp core/Uuid.cpp + core/Base32.h + core/Base32.cpp cli/PasswordInput.cpp cli/PasswordInput.h crypto/Crypto.cpp @@ -138,8 +140,6 @@ set(keepassx_SOURCES streams/qtiocompressor.cpp streams/StoreDataStream.cpp streams/SymmetricCipherStream.cpp - totp/base32.h - totp/base32.cpp totp/totp.h totp/totp.cpp ) diff --git a/src/config-keepassx.h.cmake b/src/config-keepassx.h.cmake index 9ae5f4836..e06c69382 100644 --- a/src/config-keepassx.h.cmake +++ b/src/config-keepassx.h.cmake @@ -16,6 +16,11 @@ #cmakedefine WITH_XC_AUTOTYPE #cmakedefine WITH_XC_YUBIKEY +#cmakedefine KEEPASSXC_DIST +#cmakedefine KEEPASSXC_DIST_TYPE "@KEEPASSXC_DIST_TYPE@" +#cmakedefine KEEPASSXC_DIST_SNAP +#cmakedefine KEEPASSXC_DIST_APPIMAGE + #cmakedefine HAVE_PR_SET_DUMPABLE 1 #cmakedefine HAVE_RLIMIT_CORE 1 #cmakedefine HAVE_PT_DENY_ATTACH 1 diff --git a/src/core/Base32.cpp b/src/core/Base32.cpp new file mode 100644 index 000000000..13228a37f --- /dev/null +++ b/src/core/Base32.cpp @@ -0,0 +1,290 @@ +/* + * 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 + * 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 . + */ + +/* Conforms to RFC 4648. For details, see: https://tools.ietf.org/html/rfc4648 + * Use the functions Base32::addPadding/1, Base32::removePadding/1 or + * Base32::sanitizeInput/1 to fix input or output for a particular + * applications (e.g. to use with Google Authenticator). + */ + +#include "Base32.h" + +constexpr quint64 MASK_40BIT = quint64(0xF8) << 32; +constexpr quint64 MASK_35BIT = quint64(0x7C0000000); +constexpr quint64 MASK_25BIT = quint64(0x1F00000); +constexpr quint64 MASK_20BIT = quint64(0xF8000); +constexpr quint64 MASK_10BIT = quint64(0x3E0); + +constexpr char alphabet[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567"; +constexpr quint8 ALPH_POS_2 = 26; + +constexpr quint8 ASCII_2 = static_cast('2'); +constexpr quint8 ASCII_7 = static_cast('7'); +constexpr quint8 ASCII_A = static_cast('A'); +constexpr quint8 ASCII_Z = static_cast('Z'); +constexpr quint8 ASCII_a = static_cast('a'); +constexpr quint8 ASCII_z = static_cast('z'); +constexpr quint8 ASCII_EQ = static_cast('='); + +QVariant Base32::decode(const QByteArray& encodedData) +{ + if (encodedData.size() <= 0) { + return QVariant::fromValue(QByteArray("")); + } + + if (encodedData.size() % 8 != 0) { + return QVariant(); + } + + int nPads = 0; + for (int i = -1; i > -7; --i) { + if ('=' == encodedData[encodedData.size() + i]) + ++nPads; + } + + int specialOffset; + int nSpecialBytes; + + switch (nPads) { // in {0, 1, 3, 4, 6} + case 1: + nSpecialBytes = 4; + specialOffset = 3; + break; + case 3: + nSpecialBytes = 3; + specialOffset = 1; + break; + case 4: + nSpecialBytes = 2; + specialOffset = 4; + break; + case 6: + nSpecialBytes = 1; + specialOffset = 2; + break; + default: + nSpecialBytes = 0; + specialOffset = 0; + } + + Q_ASSERT(encodedData.size() > 0); + const int nQuanta = encodedData.size() / 8; + const int nBytes = nSpecialBytes > 0 ? (nQuanta - 1) * 5 + nSpecialBytes : nQuanta * 5; + + QByteArray data(nBytes, Qt::Uninitialized); + + int i = 0; + int o = 0; + + while (i < encodedData.size()) { + quint64 quantum = 0; + int nQuantumBytes = 5; + + for (int n = 0; n < 8; ++n) { + quint8 ch = static_cast(encodedData[i++]); + if ((ASCII_A <= ch && ch <= ASCII_Z) || (ASCII_a <= ch && ch <= ASCII_z)) { + ch -= ASCII_A; + if (ch >= ALPH_POS_2) + ch -= ASCII_a - ASCII_A; + } else { + if (ASCII_2 <= ch && ch <= ASCII_7) { + ch -= ASCII_2; + ch += ALPH_POS_2; + } else { + if (ASCII_EQ == ch) { + if (i == encodedData.size()) { + // finished with special quantum + quantum >>= specialOffset; + nQuantumBytes = nSpecialBytes; + } + continue; + } else { + // illegal character + return QVariant(); + } + } + } + + quantum <<= 5; + quantum |= ch; + } + + const int offset = (nQuantumBytes - 1) * 8; + quint64 mask = quint64(0xFF) << offset; + for (int n = offset; n >= 0 && o < nBytes; n -= 8) { + data[o++] = static_cast((quantum & mask) >> n); + mask >>= 8; + } + } + + Q_ASSERT(encodedData.size() == i); + Q_ASSERT(nBytes == o); + + return QVariant::fromValue(data); +} + +QByteArray Base32::encode(const QByteArray& data) +{ + if (data.size() < 1) { + return QByteArray(); + } + + const int nBits = data.size() * 8; + const int rBits = nBits % 40; // in {0, 8, 16, 24, 32} + const int nQuanta = nBits / 40 + (rBits > 0 ? 1 : 0); + const int nBytes = nQuanta * 8; + QByteArray encodedData(nQuanta * 8, Qt::Uninitialized); + + int i = 0; + int o = 0; + int n; + quint64 mask; + quint64 quantum; + + // 40-bits of input per input group + while (i + 5 <= data.size()) { + quantum = 0; + for (n = 32; n >= 0; n -= 8) { + quantum |= (static_cast(data[i++]) << n); + } + + mask = MASK_40BIT; + int index; + for (n = 35; n >= 0; n -= 5) { + index = (quantum & mask) >> n; + encodedData[o++] = alphabet[index]; + mask >>= 5; + } + } + + // < 40-bits of input at final input group + if (i < data.size()) { + Q_ASSERT(rBits > 0); + quantum = 0; + for (n = rBits - 8; n >= 0; n -= 8) + quantum |= static_cast(data[i++]) << n; + + switch (rBits) { + case 8: // expand to 10 bits + quantum <<= 2; + mask = MASK_10BIT; + n = 5; + break; + case 16: // expand to 20 bits + quantum <<= 4; + mask = MASK_20BIT; + n = 15; + break; + case 24: // expand to 25 bits + quantum <<= 1; + mask = MASK_25BIT; + n = 20; + break; + default: // expand to 35 bits + Q_ASSERT(rBits == 32); + quantum <<= 3; + mask = MASK_35BIT; + n = 30; + } + + while (n >= 0) { + int index = (quantum & mask) >> n; + encodedData[o++] = alphabet[index]; + mask >>= 5; + n -= 5; + } + + // add pad characters + while (o < encodedData.size()) { + encodedData[o++] = '='; + } + } + + Q_ASSERT(data.size() == i); + Q_ASSERT(nBytes == o); + return encodedData; +} + +QByteArray Base32::addPadding(const QByteArray& encodedData) +{ + if (encodedData.size() <= 0 || encodedData.size() % 8 == 0) { + return encodedData; + } + + const int rBytes = encodedData.size() % 8; + // rBytes must be a member of {2, 4, 5, 7} + if (1 == rBytes || 3 == rBytes || 6 == rBytes) { + return encodedData; + } + + QByteArray newEncodedData(encodedData); + for (int nPads = 8 - rBytes; nPads > 0; --nPads) { + newEncodedData.append('='); + } + + return newEncodedData; +} + +QByteArray Base32::removePadding(const QByteArray& encodedData) +{ + if (encodedData.size() <= 0 || encodedData.size() % 8 != 0) { + return encodedData; // return same bad input + } + + int nPads = 0; + for (int i = -1; i > -7; --i) { + if ('=' == encodedData[encodedData.size() + i]) { + ++nPads; + } + } + + QByteArray newEncodedData(encodedData); + newEncodedData.remove(encodedData.size() - nPads, nPads); + newEncodedData.resize(encodedData.size() - nPads); + + return newEncodedData; +} + +QByteArray Base32::sanitizeInput(const QByteArray& encodedData) +{ + if (encodedData.size() <= 0) { + return encodedData; + } + + QByteArray newEncodedData(encodedData.size(), Qt::Uninitialized); + int i = 0; + for (auto ch : encodedData) { + switch (ch) { + case '0': + newEncodedData[i++] = 'O'; + break; + case '1': + newEncodedData[i++] = 'L'; + break; + case '8': + newEncodedData[i++] = 'B'; + break; + default: + if (('A' <= ch && ch <= 'Z') || ('a' <= ch && ch <= 'z') || ('2' <= ch && ch <= '7')) { + newEncodedData[i++] = ch; + } + } + } + newEncodedData.resize(i); + + return addPadding(newEncodedData); +} diff --git a/src/core/Base32.h b/src/core/Base32.h new file mode 100644 index 000000000..204368c52 --- /dev/null +++ b/src/core/Base32.h @@ -0,0 +1,42 @@ +/* + * 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 + * 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 . + */ + +/* Conforms to RFC 4648. For details, see: https://tools.ietf.org/html/rfc4648 + * Use the functions Base32::addPadding/1, Base32::removePadding/1 or + * Base32::sanitizeInput/1 to fix input or output for a particular + * applications (e.g. to use with Google Authenticator). + */ + +#ifndef BASE32_H +#define BASE32_H + +#include +#include +#include + +class Base32 +{ +public: + Base32() = default; + Q_REQUIRED_RESULT static QVariant decode(const QByteArray&); + Q_REQUIRED_RESULT static QByteArray encode(const QByteArray&); + Q_REQUIRED_RESULT static QByteArray addPadding(const QByteArray&); + Q_REQUIRED_RESULT static QByteArray removePadding(const QByteArray&); + Q_REQUIRED_RESULT static QByteArray sanitizeInput(const QByteArray&); +}; + +#endif // BASE32_H diff --git a/src/core/Database.cpp b/src/core/Database.cpp index d1c0fea4d..864dd758e 100644 --- a/src/core/Database.cpp +++ b/src/core/Database.cpp @@ -257,6 +257,25 @@ bool Database::hasKey() const return m_data.hasKey; } +bool Database::transformKeyWithSeed(const QByteArray& transformSeed) +{ + Q_ASSERT(hasKey()); + + bool ok; + QString errorString; + + QByteArray transformedMasterKey = + m_data.key.transform(transformSeed, transformRounds(), &ok, &errorString); + if (!ok) { + return false; + } + + m_data.transformSeed = transformSeed; + m_data.transformedMasterKey = transformedMasterKey; + + return true; +} + bool Database::verifyKey(const CompositeKey& key) const { Q_ASSERT(hasKey()); @@ -328,6 +347,15 @@ void Database::emptyRecycleBin() void Database::merge(const Database* other) { m_rootGroup->merge(other->rootGroup()); + + for (Uuid customIconId : other->metadata()->customIcons().keys()) { + QImage customIcon = other->metadata()->customIcon(customIconId); + if (!this->metadata()->containsCustomIcon(customIconId)) { + qDebug("Adding custom icon %s to database.", qPrintable(customIconId.toHex())); + this->metadata()->addCustomIcon(customIconId, customIcon); + } + } + emit modified(); } diff --git a/src/core/Database.h b/src/core/Database.h index a799e0b3b..b08233e57 100644 --- a/src/core/Database.h +++ b/src/core/Database.h @@ -106,6 +106,7 @@ public: */ bool setKey(const CompositeKey& key); bool hasKey() const; + bool transformKeyWithSeed(const QByteArray& transformSeed); bool verifyKey(const CompositeKey& key) const; void recycleEntry(Entry* entry); void recycleGroup(Group* group); diff --git a/src/core/Entry.cpp b/src/core/Entry.cpp index 7388b429e..64ce5297c 100644 --- a/src/core/Entry.cpp +++ b/src/core/Entry.cpp @@ -801,28 +801,31 @@ QString Entry::resolvePlaceholder(const QString& str) const QString Entry::resolveUrl(const QString& url) const { -#ifdef WITH_XC_HTTP QString newUrl = url; - if (!url.contains("://")) { + if (!url.isEmpty() && !url.contains("://")) { // URL doesn't have a protocol, add https by default newUrl.prepend("https://"); } - QUrl tempUrl = QUrl(newUrl); - if (tempUrl.isValid()) { - if (tempUrl.scheme() == "cmd") { - // URL is a cmd, hopefully the second argument is an URL - QStringList cmd = newUrl.split(" "); - if (cmd.size() > 1) { - return resolveUrl(cmd[1].remove("'").remove("\"")); + if (newUrl.startsWith("cmd://")) { + QStringList cmdList = newUrl.split(" "); + for (int i=1; i < cmdList.size(); ++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("'|\""))); } - } else if (tempUrl.scheme() == "http" || tempUrl.scheme() == "https") { - // URL is nice - return tempUrl.url(); } + + // No URL in this command + return QString(""); } -#else - Q_UNUSED(url); -#endif + + // Validate the URL + QUrl tempUrl = QUrl(newUrl); + if (tempUrl.isValid() && (tempUrl.scheme() == "http" || tempUrl.scheme() == "https")) { + return tempUrl.url(); + } + + // No valid http URL's found return QString(""); } diff --git a/src/core/FilePath.cpp b/src/core/FilePath.cpp index 132fdc007..b5c9d1020 100644 --- a/src/core/FilePath.cpp +++ b/src/core/FilePath.cpp @@ -91,17 +91,29 @@ QString FilePath::pluginPath(const QString& name) QIcon FilePath::applicationIcon() { +#ifdef KEEPASSXC_DIST_SNAP + return icon("apps", "keepassxc", false); +#else return icon("apps", "keepassxc"); +#endif } QIcon FilePath::trayIconLocked() { +#ifdef KEEPASSXC_DIST_SNAP + return icon("apps", "keepassxc-locked", false); +#else return icon("apps", "keepassxc-locked"); +#endif } QIcon FilePath::trayIconUnlocked() { +#ifdef KEEPASSXC_DIST_SNAP + return icon("apps", "keepassxc-unlocked", false); +#else return icon("apps", "keepassxc-unlocked"); +#endif } QIcon FilePath::icon(const QString& category, const QString& name, bool fromTheme) diff --git a/src/core/Metadata.cpp b/src/core/Metadata.cpp index eb976d0e5..6377c5846 100644 --- a/src/core/Metadata.cpp +++ b/src/core/Metadata.cpp @@ -454,7 +454,7 @@ void Metadata::copyCustomIcons(const QSet& iconList, const Metadata* other QByteArray Metadata::hashImage(const QImage& image) { - auto data = QByteArray((char*)image.bits(), image.byteCount()); + auto data = QByteArray(reinterpret_cast(image.bits()), image.byteCount()); return QCryptographicHash::hash(data, QCryptographicHash::Md5); } diff --git a/src/crypto/SymmetricCipher.h b/src/crypto/SymmetricCipher.h index 0070ed7de..b85c58b7c 100644 --- a/src/crypto/SymmetricCipher.h +++ b/src/crypto/SymmetricCipher.h @@ -59,11 +59,11 @@ public: return m_backend->process(data, ok); } - inline bool processInPlace(QByteArray& data) Q_REQUIRED_RESULT { + Q_REQUIRED_RESULT inline bool processInPlace(QByteArray& data) { return m_backend->processInPlace(data); } - inline bool processInPlace(QByteArray& data, quint64 rounds) Q_REQUIRED_RESULT { + Q_REQUIRED_RESULT inline bool processInPlace(QByteArray& data, quint64 rounds) { Q_ASSERT(rounds > 0); return m_backend->processInPlace(data, rounds); } diff --git a/src/crypto/SymmetricCipherBackend.h b/src/crypto/SymmetricCipherBackend.h index 8f19b8ed0..78ec60c60 100644 --- a/src/crypto/SymmetricCipherBackend.h +++ b/src/crypto/SymmetricCipherBackend.h @@ -29,8 +29,8 @@ public: virtual bool setIv(const QByteArray& iv) = 0; virtual QByteArray process(const QByteArray& data, bool* ok) = 0; - virtual bool processInPlace(QByteArray& data) Q_REQUIRED_RESULT = 0; - virtual bool processInPlace(QByteArray& data, quint64 rounds) Q_REQUIRED_RESULT = 0; + Q_REQUIRED_RESULT virtual bool processInPlace(QByteArray& data) = 0; + Q_REQUIRED_RESULT virtual bool processInPlace(QByteArray& data, quint64 rounds) = 0; virtual bool reset() = 0; virtual int blockSize() const = 0; diff --git a/src/crypto/SymmetricCipherGcrypt.cpp b/src/crypto/SymmetricCipherGcrypt.cpp index cd4324065..e600a7edb 100644 --- a/src/crypto/SymmetricCipherGcrypt.cpp +++ b/src/crypto/SymmetricCipherGcrypt.cpp @@ -148,9 +148,10 @@ QByteArray SymmetricCipherGcrypt::process(const QByteArray& data, bool* ok) if (error != 0) { setErrorString(error); *ok = false; + } else { + *ok = true; } - *ok = true; return result; } diff --git a/src/crypto/SymmetricCipherGcrypt.h b/src/crypto/SymmetricCipherGcrypt.h index 367ee5b95..d3ad8d15b 100644 --- a/src/crypto/SymmetricCipherGcrypt.h +++ b/src/crypto/SymmetricCipherGcrypt.h @@ -35,8 +35,8 @@ public: bool setIv(const QByteArray& iv); QByteArray process(const QByteArray& data, bool* ok); - bool processInPlace(QByteArray& data) Q_REQUIRED_RESULT; - bool processInPlace(QByteArray& data, quint64 rounds) Q_REQUIRED_RESULT; + Q_REQUIRED_RESULT bool processInPlace(QByteArray& data); + Q_REQUIRED_RESULT bool processInPlace(QByteArray& data, quint64 rounds); bool reset(); int blockSize() const; diff --git a/src/format/KeePass2RandomStream.h b/src/format/KeePass2RandomStream.h index 022c8399f..584d738b3 100644 --- a/src/format/KeePass2RandomStream.h +++ b/src/format/KeePass2RandomStream.h @@ -29,7 +29,7 @@ public: bool init(const QByteArray& key); QByteArray randomBytes(int size, bool* ok); QByteArray process(const QByteArray& data, bool* ok); - bool processInPlace(QByteArray& data) Q_REQUIRED_RESULT; + Q_REQUIRED_RESULT bool processInPlace(QByteArray& data); QString errorString() const; private: diff --git a/src/format/KeePass2Writer.cpp b/src/format/KeePass2Writer.cpp index d63151c84..f8f60f11e 100644 --- a/src/format/KeePass2Writer.cpp +++ b/src/format/KeePass2Writer.cpp @@ -45,6 +45,7 @@ void KeePass2Writer::writeDatabase(QIODevice* device, Database* db) m_error = false; m_errorStr.clear(); + QByteArray transformSeed = randomGen()->randomArray(32); QByteArray masterSeed = randomGen()->randomArray(32); QByteArray encryptionIV = randomGen()->randomArray(16); QByteArray protectedStreamKey = randomGen()->randomArray(32); @@ -52,7 +53,12 @@ void KeePass2Writer::writeDatabase(QIODevice* device, Database* db) QByteArray endOfHeader = "\r\n\r\n"; if (db->challengeMasterSeed(masterSeed) == false) { - raiseError("Unable to issue challenge-response."); + raiseError(tr("Unable to issue challenge-response.")); + return; + } + + if (!db->transformKeyWithSeed(transformSeed)) { + raiseError(tr("Unable to calculate master key")); return; } diff --git a/src/format/KeePass2Writer.h b/src/format/KeePass2Writer.h index 1b3436dc6..184aa1a71 100644 --- a/src/format/KeePass2Writer.h +++ b/src/format/KeePass2Writer.h @@ -18,6 +18,8 @@ #ifndef KEEPASSX_KEEPASS2WRITER_H #define KEEPASSX_KEEPASS2WRITER_H +#include + #include "format/KeePass2.h" #include "keys/CompositeKey.h" @@ -26,6 +28,8 @@ class QIODevice; class KeePass2Writer { + Q_DECLARE_TR_FUNCTIONS(KeePass2Writer) + public: KeePass2Writer(); void writeDatabase(QIODevice* device, Database* db); diff --git a/src/gui/AboutDialog.cpp b/src/gui/AboutDialog.cpp index 0e0f2960a..5978cd956 100644 --- a/src/gui/AboutDialog.cpp +++ b/src/gui/AboutDialog.cpp @@ -55,10 +55,14 @@ AboutDialog::AboutDialog(QWidget* parent) QString debugInfo = "KeePassXC - "; debugInfo.append(tr("Version %1\n").arg(KEEPASSX_VERSION)); if (!commitHash.isEmpty()) { - debugInfo.append(tr("Revision: %1").arg(commitHash).append("\n\n")); + debugInfo.append(tr("Revision: %1").arg(commitHash.left(7)).append("\n")); } - debugInfo.append(QString("%1\n- Qt %2\n- %3\n\n") +#ifdef KEEPASSXC_DIST + debugInfo.append(tr("Distribution: %1").arg(KEEPASSXC_DIST_TYPE).append("\n")); +#endif + + debugInfo.append("\n").append(QString("%1\n- Qt %2\n- %3\n\n") .arg(tr("Libraries:")) .arg(QString::fromLocal8Bit(qVersion())) .arg(Crypto::backendVersion())); diff --git a/src/gui/DatabaseOpenWidget.cpp b/src/gui/DatabaseOpenWidget.cpp index 7d59f16cf..ee0e9de26 100644 --- a/src/gui/DatabaseOpenWidget.cpp +++ b/src/gui/DatabaseOpenWidget.cpp @@ -70,9 +70,6 @@ DatabaseOpenWidget::DatabaseOpenWidget(QWidget* parent) connect(m_ui->buttonRedetectYubikey, SIGNAL(clicked()), SLOT(pollYubikey())); connect(m_ui->comboChallengeResponse, SIGNAL(activated(int)), SLOT(activateChallengeResponse())); - - connect(YubiKey::instance(), SIGNAL(detected(int,bool)), SLOT(yubikeyDetected(int,bool)), Qt::QueuedConnection); - connect(YubiKey::instance(), SIGNAL(notFound()), SLOT(noYubikeyFound()), Qt::QueuedConnection); #else m_ui->checkChallengeResponse->setVisible(false); m_ui->buttonRedetectYubikey->setVisible(false); @@ -98,10 +95,24 @@ void DatabaseOpenWidget::showEvent(QShowEvent* event) m_ui->editPassword->setFocus(); #ifdef WITH_XC_YUBIKEY + connect(YubiKey::instance(), SIGNAL(detected(int,bool)), SLOT(yubikeyDetected(int,bool)), Qt::QueuedConnection); + connect(YubiKey::instance(), SIGNAL(detectComplete()), SLOT(yubikeyDetectComplete()), Qt::QueuedConnection); + connect(YubiKey::instance(), SIGNAL(notFound()), SLOT(noYubikeyFound()), Qt::QueuedConnection); + pollYubikey(); #endif } +void DatabaseOpenWidget::hideEvent(QHideEvent* event) +{ + DialogyWidget::hideEvent(event); + +#ifdef WITH_XC_YUBIKEY + // Don't listen to any Yubikey events if we are hidden + disconnect(YubiKey::instance(), 0, this, 0); +#endif +} + void DatabaseOpenWidget::load(const QString& filename) { m_filename = filename; @@ -151,7 +162,10 @@ void DatabaseOpenWidget::enterKey(const QString& pw, const QString& keyFile) void DatabaseOpenWidget::openDatabase() { KeePass2Reader reader; - CompositeKey masterKey = databaseKey(); + QSharedPointer masterKey = databaseKey(); + if (masterKey.isNull()) { + return; + } QFile file(m_filename); if (!file.open(QIODevice::ReadOnly)) { @@ -163,7 +177,7 @@ void DatabaseOpenWidget::openDatabase() delete m_db; } QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); - m_db = reader.readDatabase(&file, masterKey); + m_db = reader.readDatabase(&file, *masterKey); QApplication::restoreOverrideCursor(); if (m_db) { @@ -171,20 +185,19 @@ void DatabaseOpenWidget::openDatabase() m_ui->messageWidget->animatedHide(); } emit editFinished(true); - } - else { - m_ui->messageWidget->showMessage(tr("Unable to open the database.") - .append("\n").append(reader.errorString()), MessageWidget::Error); + } else { + m_ui->messageWidget->showMessage(tr("Unable to open the database.").append("\n").append(reader.errorString()), + MessageWidget::Error); m_ui->editPassword->clear(); } } -CompositeKey DatabaseOpenWidget::databaseKey() +QSharedPointer DatabaseOpenWidget::databaseKey() { - CompositeKey masterKey; + auto masterKey = QSharedPointer::create(); if (m_ui->checkPassword->isChecked()) { - masterKey.addKey(PasswordKey(m_ui->editPassword->text())); + masterKey->addKey(PasswordKey(m_ui->editPassword->text())); } QHash lastKeyFiles = config()->get("LastKeyFiles").toHash(); @@ -195,11 +208,11 @@ CompositeKey DatabaseOpenWidget::databaseKey() QString keyFilename = m_ui->comboKeyFile->currentText(); QString errorMsg; if (!key.load(keyFilename, &errorMsg)) { - m_ui->messageWidget->showMessage(tr("Can't open key file").append(":\n") - .append(errorMsg), MessageWidget::Error); - return CompositeKey(); + m_ui->messageWidget->showMessage(tr("Can't open key file").append(":\n").append(errorMsg), + MessageWidget::Error); + return QSharedPointer(); } - masterKey.addKey(key); + masterKey->addKey(key); lastKeyFiles[m_filename] = keyFilename; } else { lastKeyFiles.remove(m_filename); @@ -226,9 +239,9 @@ CompositeKey DatabaseOpenWidget::databaseKey() // read blocking mode from LSB and slot index number from second LSB bool blocking = comboPayload & 1; - int slot = comboPayload >> 1; - auto key = QSharedPointer(new YkChallengeResponseKey(slot, blocking)); - masterKey.addChallengeResponseKey(key); + int slot = comboPayload >> 1; + auto key = QSharedPointer(new YkChallengeResponseKey(slot, blocking)); + masterKey->addChallengeResponseKey(key); } #endif @@ -283,10 +296,6 @@ void DatabaseOpenWidget::yubikeyDetected(int slot, bool blocking) YkChallengeResponseKey yk(slot, blocking); // add detected YubiKey to combo box and encode blocking mode in LSB, slot number in second LSB m_ui->comboChallengeResponse->addItem(yk.getName(), QVariant((slot << 1) | blocking)); - m_ui->comboChallengeResponse->setEnabled(true); - m_ui->checkChallengeResponse->setEnabled(true); - m_ui->buttonRedetectYubikey->setEnabled(true); - m_ui->yubikeyProgress->setVisible(false); if (config()->get("RememberLastKeyFiles").toBool()) { QHash lastChallengeResponse = config()->get("LastChallengeResponse").toHash(); @@ -296,6 +305,14 @@ void DatabaseOpenWidget::yubikeyDetected(int slot, bool blocking) } } +void DatabaseOpenWidget::yubikeyDetectComplete() +{ + m_ui->comboChallengeResponse->setEnabled(true); + m_ui->checkChallengeResponse->setEnabled(true); + m_ui->buttonRedetectYubikey->setEnabled(true); + m_ui->yubikeyProgress->setVisible(false); +} + void DatabaseOpenWidget::noYubikeyFound() { m_ui->buttonRedetectYubikey->setEnabled(true); diff --git a/src/gui/DatabaseOpenWidget.h b/src/gui/DatabaseOpenWidget.h index 441e6418c..a7691a91e 100644 --- a/src/gui/DatabaseOpenWidget.h +++ b/src/gui/DatabaseOpenWidget.h @@ -51,7 +51,8 @@ signals: protected: void showEvent(QShowEvent* event) override; - CompositeKey databaseKey(); + void hideEvent(QHideEvent* event) override; + QSharedPointer databaseKey(); protected slots: virtual void openDatabase(); @@ -63,6 +64,7 @@ private slots: void activateChallengeResponse(); void browseKeyFile(); void yubikeyDetected(int slot, bool blocking); + void yubikeyDetectComplete(); void noYubikeyFound(); protected: diff --git a/src/gui/DatabaseTabWidget.cpp b/src/gui/DatabaseTabWidget.cpp index 9dca1ac06..4c9445ccc 100644 --- a/src/gui/DatabaseTabWidget.cpp +++ b/src/gui/DatabaseTabWidget.cpp @@ -129,7 +129,12 @@ void DatabaseTabWidget::openDatabase(const QString& fileName, const QString& pw, while (i.hasNext()) { i.next(); if (i.value().canonicalFilePath == canonicalFilePath) { - setCurrentIndex(databaseIndex(i.key())); + if (!i.value().dbWidget->dbHasKey() && !(pw.isNull() && keyFile.isEmpty())) { + // If the database is locked and a pw or keyfile is provided, unlock it + i.value().dbWidget->switchToOpenDatabase(i.value().filePath, pw, keyFile); + } else { + setCurrentIndex(databaseIndex(i.key())); + } return; } } @@ -181,6 +186,7 @@ void DatabaseTabWidget::openDatabase(const QString& fileName, const QString& pw, lockFile->tryLock(); } } else { + delete lockFile; return; } } @@ -203,7 +209,7 @@ void DatabaseTabWidget::openDatabase(const QString& fileName, const QString& pw, updateLastDatabases(dbStruct.filePath); - if (!pw.isNull() || !keyFile.isEmpty()) { + if (!(pw.isNull() && keyFile.isEmpty())) { dbStruct.dbWidget->switchToOpenDatabase(dbStruct.filePath, pw, keyFile); } else { diff --git a/src/gui/EditWidgetIcons.cpp b/src/gui/EditWidgetIcons.cpp index 691e93210..7c01b31f1 100644 --- a/src/gui/EditWidgetIcons.cpp +++ b/src/gui/EditWidgetIcons.cpp @@ -302,6 +302,7 @@ void EditWidgetIcons::addCustomIcon(const QImage &icon) } // Select the new or existing icon + updateRadioButtonCustomIcons(); QModelIndex index = m_customIconModel->indexFromUuid(uuid); m_ui->customIconsView->setCurrentIndex(index); } diff --git a/src/gui/SettingsWidget.cpp b/src/gui/SettingsWidget.cpp index e396f6043..420778be4 100644 --- a/src/gui/SettingsWidget.cpp +++ b/src/gui/SettingsWidget.cpp @@ -156,7 +156,7 @@ void SettingsWidget::loadSettings() m_secUi->lockDatabaseIdleSpinBox->setValue(config()->get("security/lockdatabaseidlesec").toInt()); m_secUi->lockDatabaseMinimizeCheckBox->setChecked(config()->get("security/lockdatabaseminimize").toBool()); m_secUi->lockDatabaseOnScreenLockCheckBox->setChecked(config()->get("security/lockdatabasescreenlock").toBool()); - m_secUi->lockDatabaseOnScreenLockCheckBox->setChecked(config()->get("security/IconDownloadFallbackToGoogle").toBool()); + m_secUi->fallbackToGoogle->setChecked(config()->get("security/IconDownloadFallbackToGoogle").toBool()); m_secUi->passwordCleartextCheckBox->setChecked(config()->get("security/passwordscleartext").toBool()); m_secUi->passwordRepeatCheckBox->setChecked(config()->get("security/passwordsrepeat").toBool()); diff --git a/src/keys/drivers/YubiKey.cpp b/src/keys/drivers/YubiKey.cpp index b6f0d3098..4b98a6e48 100644 --- a/src/keys/drivers/YubiKey.cpp +++ b/src/keys/drivers/YubiKey.cpp @@ -25,6 +25,7 @@ #include #include +#include "core/Tools.h" #include "core/Global.h" #include "crypto/Random.h" @@ -112,23 +113,36 @@ bool YubiKey::deinit() void YubiKey::detect() { - if (init()) { - for (int i = 1; i < 3; i++) { - YubiKey::ChallengeResult result; - QByteArray rand = randomGen()->randomArray(1); - QByteArray resp; + bool found = false; + if (init()) { + YubiKey::ChallengeResult result; + QByteArray rand = randomGen()->randomArray(1); + QByteArray resp; + + // Check slot 1 and 2 for Challenge-Response HMAC capability + for (int i = 1; i <= 2; ++i) { result = challenge(i, false, rand, resp); - if (result == YubiKey::ALREADY_RUNNING) { - emit alreadyRunning(); - return; - } else if (result != YubiKey::ERROR) { - emit detected(i, result == YubiKey::WOULDBLOCK); - return; + if (result == ALREADY_RUNNING) { + // Try this slot again after waiting + Tools::sleep(300); + result = challenge(i, false, rand, resp); } + + if (result != ALREADY_RUNNING && result != ERROR) { + emit detected(i, result == WOULDBLOCK); + found = true; + } + // Wait between slots to let the yubikey settle + Tools::sleep(150); } } - emit notFound(); + + if (!found) { + emit notFound(); + } else { + emit detectComplete(); + } } bool YubiKey::getSerial(unsigned int& serial) @@ -160,6 +174,7 @@ YubiKey::ChallengeResult YubiKey::challenge(int slot, bool mayBlock, const QByte } // yk_challenge_response() insists on 64 byte response buffer */ + response.clear(); response.resize(64); /* The challenge sent to the yubikey should always be 64 bytes for diff --git a/src/keys/drivers/YubiKey.h b/src/keys/drivers/YubiKey.h index 1467b9fd1..328688f08 100644 --- a/src/keys/drivers/YubiKey.h +++ b/src/keys/drivers/YubiKey.h @@ -87,6 +87,11 @@ signals: */ void detected(int slot, bool blocking); + /** + * Emitted when detection is complete + */ + void detectComplete(); + /** * Emitted when the YubiKey was challenged and has returned a response. */ diff --git a/src/totp/base32.cpp b/src/totp/base32.cpp deleted file mode 100644 index 4c81cb491..000000000 --- a/src/totp/base32.cpp +++ /dev/null @@ -1,68 +0,0 @@ -// Base32 implementation -// Source: https://github.com/google/google-authenticator-libpam/blob/master/src/base32.c -// -// Copyright 2010 Google Inc. -// Author: Markus Gutschke -// Modifications Copyright 2017 KeePassXC team -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "base32.h" - -Base32::Base32() -{ -} - -QByteArray Base32::base32_decode(const QByteArray encoded) -{ - QByteArray result; - - int buffer = 0; - int bitsLeft = 0; - - for (char ch : encoded) { - if (ch == 0 || ch == ' ' || ch == '\t' || ch == '\r' || ch == '\n' || ch == '-' || ch == '=') { - continue; - } - - buffer <<= 5; - - // Deal with commonly mistyped characters - if (ch == '0') { - ch = 'O'; - } else if (ch == '1') { - ch = 'L'; - } else if (ch == '8') { - ch = 'B'; - } - - // Look up one base32 digit - if ((ch >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z')) { - ch = (ch & 0x1F) - 1; - } else if (ch >= '2' && ch <= '7') { - ch -= '2' - 26; - } else { - return QByteArray(); - } - - buffer |= ch; - bitsLeft += 5; - - if (bitsLeft >= 8) { - result.append(static_cast (buffer >> (bitsLeft - 8))); - bitsLeft -= 8; - } - } - - return result; -} \ No newline at end of file diff --git a/src/totp/base32.h b/src/totp/base32.h deleted file mode 100644 index 75343fa43..000000000 --- a/src/totp/base32.h +++ /dev/null @@ -1,34 +0,0 @@ -// Base32 implementation -// Source: https://github.com/google/google-authenticator-libpam/blob/master/src/base32.h -// -// Copyright 2010 Google Inc. -// Author: Markus Gutschke -// Modifications Copyright 2017 KeePassXC team -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef BASE32_H -#define BASE32_H - -#include -#include - -class Base32 -{ -public: - Base32(); - static QByteArray base32_decode(const QByteArray encoded); -}; - - -#endif //BASE32_H diff --git a/src/totp/totp.cpp b/src/totp/totp.cpp index 51af0e086..7a584def2 100644 --- a/src/totp/totp.cpp +++ b/src/totp/totp.cpp @@ -17,16 +17,16 @@ */ #include "totp.h" -#include "base32.h" -#include -#include -#include -#include +#include "core/Base32.h" #include +#include #include +#include #include #include - +#include +#include +#include const quint8 QTotp::defaultStep = 30; const quint8 QTotp::defaultDigits = 6; @@ -35,7 +35,7 @@ QTotp::QTotp() { } -QString QTotp::parseOtpString(QString key, quint8 &digits, quint8 &step) +QString QTotp::parseOtpString(QString key, quint8& digits, quint8& step) { QUrl url(key); @@ -58,7 +58,6 @@ QString QTotp::parseOtpString(QString key, quint8 &digits, quint8 &step) step = q_step; } - } else { // Compatibility with "KeeOtp" plugin string format QRegExp rx("key=(.+)", Qt::CaseInsensitive, QRegExp::RegExp); @@ -93,30 +92,59 @@ QString QTotp::parseOtpString(QString key, quint8 &digits, quint8 &step) return seed; } -QString QTotp::generateTotp(const QByteArray key, quint64 time, - const quint8 numDigits = defaultDigits, const quint8 step = defaultStep) +QString QTotp::generateTotp(const QByteArray key, + quint64 time, + const quint8 numDigits = defaultDigits, + const quint8 step = defaultStep) { quint64 current = qToBigEndian(time / step); - QByteArray secret = Base32::base32_decode(key); - if (secret.isEmpty()) { + QVariant secret = Base32::decode(Base32::sanitizeInput(key)); + if (secret.isNull()) { return "Invalid TOTP secret key"; } QMessageAuthenticationCode code(QCryptographicHash::Sha1); - code.setKey(secret); + code.setKey(secret.toByteArray()); code.addData(QByteArray(reinterpret_cast(¤t), sizeof(current))); QByteArray hmac = code.result(); int offset = (hmac[hmac.length() - 1] & 0xf); + + // clang-format off int binary = ((hmac[offset] & 0x7f) << 24) | ((hmac[offset + 1] & 0xff) << 16) | ((hmac[offset + 2] & 0xff) << 8) | (hmac[offset + 3] & 0xff); + // clang-format on quint32 digitsPower = pow(10, numDigits); quint64 password = binary % digitsPower; return QString("%1").arg(password, numDigits, 10, QChar('0')); } + +// See: https://github.com/google/google-authenticator/wiki/Key-Uri-Format +QUrl QTotp::generateOtpString(const QString& secret, + const QString& type, + const QString& issuer, + const QString& username, + const QString& algorithm, + const quint8& digits, + const quint8& step) +{ + QUrl keyUri; + keyUri.setScheme("otpauth"); + keyUri.setHost(type); + keyUri.setPath(QString("/%1:%2").arg(issuer).arg(username)); + QUrlQuery parameters; + parameters.addQueryItem("secret", secret); + parameters.addQueryItem("issuer", issuer); + parameters.addQueryItem("algorithm", algorithm); + parameters.addQueryItem("digits", QString::number(digits)); + parameters.addQueryItem("period", QString::number(step)); + keyUri.setQuery(parameters); + + return keyUri; +} diff --git a/src/totp/totp.h b/src/totp/totp.h index 642b4f9a3..d5d8aa679 100644 --- a/src/totp/totp.h +++ b/src/totp/totp.h @@ -21,12 +21,21 @@ #include +class QUrl; + class QTotp { public: QTotp(); - static QString parseOtpString(QString rawSecret, quint8 &digits, quint8 &step); + static QString parseOtpString(QString rawSecret, quint8& digits, quint8& step); static QString generateTotp(const QByteArray key, quint64 time, const quint8 numDigits, const quint8 step); + static QUrl generateOtpString(const QString& secret, + const QString& type, + const QString& issuer, + const QString& username, + const QString& algorithm, + const quint8& digits, + const quint8& step); static const quint8 defaultStep; static const quint8 defaultDigits; }; diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 2a420270a..3f003f01c 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -161,6 +161,9 @@ add_unit_test(NAME testentry SOURCES TestEntry.cpp add_unit_test(NAME testtotp SOURCES TestTotp.cpp LIBS ${TEST_LIBRARIES}) +add_unit_test(NAME testbase32 SOURCES TestBase32.cpp + LIBS ${TEST_LIBRARIES}) + add_unit_test(NAME testcsvparser SOURCES TestCsvParser.cpp LIBS ${TEST_LIBRARIES}) diff --git a/tests/TestBase32.cpp b/tests/TestBase32.cpp new file mode 100644 index 000000000..1d30e7817 --- /dev/null +++ b/tests/TestBase32.cpp @@ -0,0 +1,330 @@ +/* + * 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 + * 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 "TestBase32.h" +#include "core/Base32.h" +#include + +QTEST_GUILESS_MAIN(TestBase32) + +void TestBase32::testDecode() +{ + // 3 quanta, all upper case + padding + QByteArray encodedData = "JBSWY3DPEB3W64TMMQXC4LQ="; + QVariant data = Base32::decode(encodedData); + QString expectedData = "Hello world..."; + QVERIFY(!data.isNull()); + QCOMPARE(data.toString(), expectedData); + QVERIFY(data.value().size() == expectedData.size()); + + // 4 quanta, all upper case + encodedData = "GEZDGNBVGY3TQOJQGEZDGNBVGY3TQOJQ"; + data = Base32::decode(encodedData); + expectedData = "12345678901234567890"; + QVERIFY(!data.isNull()); + QCOMPARE(data.toString(), expectedData); + QVERIFY(data.value().size() == expectedData.size()); + + // 4 quanta, all lower case + encodedData = "gezdgnbvgy3tqojqgezdgnbvgy3tqojq"; + data = Base32::decode(encodedData); + expectedData = "12345678901234567890"; + QVERIFY(!data.isNull()); + QCOMPARE(data.toString(), expectedData); + QVERIFY(data.value().size() == expectedData.size()); + + // 4 quanta, mixed upper and lower case + encodedData = "Gezdgnbvgy3tQojqgezdGnbvgy3tQojQ"; + data = Base32::decode(encodedData); + expectedData = "12345678901234567890"; + QVERIFY(!data.isNull()); + QCOMPARE(data.toString(), expectedData); + QVERIFY(data.value().size() == expectedData.size()); + + // 1 pad characters + encodedData = "ORSXG5A="; + data = Base32::decode(encodedData); + expectedData = "test"; + QVERIFY(!data.isNull()); + QCOMPARE(data.toString(), expectedData); + QVERIFY(data.value().size() == expectedData.size()); + + // 3 pad characters + encodedData = "L5PV6==="; + data = Base32::decode(encodedData); + expectedData = "___"; + QVERIFY(!data.isNull()); + QCOMPARE(data.toString(), expectedData); + QVERIFY(data.value().size() == expectedData.size()); + + // 4 pad characters + encodedData = "MZXW6IDCMFZA===="; + data = Base32::decode(encodedData); + expectedData = "foo bar"; + QVERIFY(!data.isNull()); + QCOMPARE(data.toString(), expectedData); + QVERIFY(data.value().size() == expectedData.size()); + + // six pad characters + encodedData = "MZXW6YTBOI======"; + data = Base32::decode(encodedData); + expectedData = "foobar"; + QVERIFY(!data.isNull()); + QCOMPARE(data.toString(), expectedData); + QVERIFY(data.value().size() == expectedData.size()); + + encodedData = "IA======"; + data = Base32::decode(encodedData); + expectedData = "@"; + QVERIFY(!data.isNull()); + QCOMPARE(data.toString(), expectedData); + QVERIFY(data.value().size() == expectedData.size()); + + // error: illegal character + encodedData = "1MZXW6YTBOI====="; + data = Base32::decode(encodedData); + QVERIFY(data.isNull()); + + // error: missing pad character + encodedData = "MZXW6YTBOI====="; + data = Base32::decode(encodedData); + QVERIFY(data.isNull()); + + // RFC 4648 test vectors + encodedData = ""; + data = Base32::decode(encodedData); + expectedData = ""; + QVERIFY(!data.isNull()); + QCOMPARE(data.toString(), expectedData); + QVERIFY(data.value().size() == expectedData.size()); + + encodedData = "MY======"; + data = Base32::decode(encodedData); + expectedData = "f"; + QVERIFY(!data.isNull()); + QCOMPARE(data.toString(), expectedData); + QVERIFY(data.value().size() == expectedData.size()); + + encodedData = "MZXQ===="; + data = Base32::decode(encodedData); + expectedData = "fo"; + QVERIFY(!data.isNull()); + QCOMPARE(data.toString(), expectedData); + QVERIFY(data.value().size() == expectedData.size()); + + encodedData = "MZXW6==="; + data = Base32::decode(encodedData); + QVERIFY(!data.isNull()); + expectedData = "foo"; + QCOMPARE(data.toString(), expectedData); + QVERIFY(data.value().size() == expectedData.size()); + + encodedData = "MZXW6YQ="; + data = Base32::decode(encodedData); + expectedData = "foob"; + QVERIFY(!data.isNull()); + QCOMPARE(data.toString(), expectedData); + QVERIFY(data.value().size() == expectedData.size()); + + encodedData = "MZXW6YTB"; + expectedData = "fooba"; + data = Base32::decode(encodedData); + QVERIFY(!data.isNull()); + QCOMPARE(data.toString(), expectedData); + QVERIFY(data.value().size() == expectedData.size()); + + encodedData = "MZXW6YTBOI======"; + data = Base32::decode(encodedData); + expectedData = "foobar"; + QVERIFY(!data.isNull()); + QCOMPARE(data.toString(), expectedData); + QVERIFY(data.value().size() == expectedData.size()); +} + +void TestBase32::testEncode() +{ + QByteArray data = "Hello world..."; + QByteArray encodedData = Base32::encode(data); + QCOMPARE(encodedData, QByteArray("JBSWY3DPEB3W64TMMQXC4LQ=")); + + data = "12345678901234567890"; + encodedData = Base32::encode(data); + QCOMPARE(encodedData, QByteArray("GEZDGNBVGY3TQOJQGEZDGNBVGY3TQOJQ")); + + data = "012345678901234567890"; + encodedData = Base32::encode(data); + QCOMPARE(encodedData, QByteArray("GAYTEMZUGU3DOOBZGAYTEMZUGU3DOOBZGA======")); + + data = "test"; + encodedData = Base32::encode(data); + QCOMPARE(encodedData, QByteArray("ORSXG5A=")); + + data = "___"; + encodedData = Base32::encode(data); + QCOMPARE(encodedData, QByteArray("L5PV6===")); + + data = "foo bar"; + encodedData = Base32::encode(data); + QCOMPARE(encodedData, QByteArray("MZXW6IDCMFZA====")); + + data = "@"; + encodedData = Base32::encode(data); + QCOMPARE(encodedData, QByteArray("IA======")); + + // RFC 4648 test vectors + data = ""; + encodedData = Base32::encode(data); + QCOMPARE(encodedData, QByteArray("")); + + data = "f"; + encodedData = Base32::encode(data); + QCOMPARE(encodedData, QByteArray("MY======")); + + data = "fo"; + encodedData = Base32::encode(data); + QCOMPARE(encodedData, QByteArray("MZXQ====")); + + data = "foo"; + encodedData = Base32::encode(data); + QCOMPARE(encodedData, QByteArray("MZXW6===")); + + data = "foob"; + encodedData = Base32::encode(data); + QCOMPARE(encodedData, QByteArray("MZXW6YQ=")); + + data = "fooba"; + encodedData = Base32::encode(data); + QCOMPARE(encodedData, QByteArray("MZXW6YTB")); + + data = "foobar"; + encodedData = Base32::encode(data); + QCOMPARE(encodedData, QByteArray("MZXW6YTBOI======")); +} + +void TestBase32::testAddPadding() +{ + // Empty. Invalid, returns input. + QByteArray data = ""; + QByteArray paddedData = Base32::addPadding(data); + QCOMPARE(paddedData, data); + + // One byte of encoded data. Invalid, returns input. + data = "B"; + paddedData = Base32::addPadding(data); + QCOMPARE(paddedData, data); + + // Two bytes of encoded data. + data = "BB"; + paddedData = Base32::addPadding(data); + QCOMPARE(paddedData, QByteArray("BB======")); + + // Three bytes of encoded data. Invalid, returns input. + data = "BBB"; + paddedData = Base32::addPadding(data); + QCOMPARE(paddedData, data); + + // Four bytes of encoded data. + data = "BBBB"; + paddedData = Base32::addPadding(data); + QCOMPARE(paddedData, QByteArray("BBBB====")); + + // Five bytes of encoded data. + data = "BBBBB"; + paddedData = Base32::addPadding(data); + QCOMPARE(paddedData, QByteArray("BBBBB===")); + + // Six bytes of encoded data. Invalid, returns input. + data = "BBBBBB"; + paddedData = Base32::addPadding(data); + QCOMPARE(paddedData, data); + + // Seven bytes of encoded data. + data = "BBBBBBB"; + paddedData = Base32::addPadding(data); + QCOMPARE(paddedData, QByteArray("BBBBBBB=")); + + // Eight bytes of encoded data. Valid, but returns same as input. + data = "BBBBBBBB"; + paddedData = Base32::addPadding(data); + QCOMPARE(paddedData, data); + + // More than eight bytes (8+5). + data = "AAAAAAAABBBBB"; + paddedData = Base32::addPadding(data); + QCOMPARE(paddedData, QByteArray("AAAAAAAABBBBB===")); +} + +void TestBase32::testRemovePadding() +{ + QByteArray data = ""; + QByteArray unpaddedData = Base32::removePadding(data); + QCOMPARE(unpaddedData, data); + + data = "AAAAAAAABB======"; + unpaddedData = Base32::removePadding(data); + QCOMPARE(unpaddedData, QByteArray("AAAAAAAABB")); + + data = "BBBB===="; + unpaddedData = Base32::removePadding(data); + QCOMPARE(unpaddedData, QByteArray("BBBB")); + + data = "AAAAAAAABBBBB==="; + unpaddedData = Base32::removePadding(data); + QCOMPARE(unpaddedData, QByteArray("AAAAAAAABBBBB")); + + data = "BBBBBBB="; + unpaddedData = Base32::removePadding(data); + QCOMPARE(unpaddedData, QByteArray("BBBBBBB")); + + // Invalid: 7 bytes of data. Returns same as input. + data = "IIIIIII"; + unpaddedData = Base32::removePadding(data); + QCOMPARE(unpaddedData, data); + + // Invalid: more padding than necessary. Returns same as input. + data = "AAAAAAAABBBB====="; + unpaddedData = Base32::removePadding(data); + QCOMPARE(unpaddedData, data); +} + +void TestBase32::testSanitizeInput() +{ + // sanitize input (white space + missing padding) + QByteArray encodedData = "JBSW Y3DP EB3W 64TM MQXC 4LQA"; + auto data = Base32::decode(Base32::sanitizeInput(encodedData)); + QVERIFY(!data.isNull()); + QCOMPARE(data.toString(), QString("Hello world...")); + + // sanitize input (typo + missing padding) + encodedData = "J8SWY3DPE83W64TMMQXC4LQA"; + data = Base32::decode(Base32::sanitizeInput(encodedData)); + QVERIFY(!data.isNull()); + QCOMPARE(data.toString(), QString("Hello world...")); + + // sanitize input (other illegal characters) + encodedData = "J8SWY3D[PE83W64TMMQ]XC!4LQA"; + data = Base32::decode(Base32::sanitizeInput(encodedData)); + QVERIFY(!data.isNull()); + QCOMPARE(data.toString(), QString("Hello world...")); + + // sanitize input (NUL character) + encodedData = "J8SWY3DPE83W64TMMQXC4LQA"; + encodedData.insert(3, '\0'); + data = Base32::decode(Base32::sanitizeInput(encodedData)); + QVERIFY(!data.isNull()); + QCOMPARE(data.toString(), QString("Hello world...")); +} diff --git a/tests/TestBase32.h b/tests/TestBase32.h new file mode 100644 index 000000000..cf7cf092c --- /dev/null +++ b/tests/TestBase32.h @@ -0,0 +1,37 @@ +/* + * 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 + * 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_TESTBASE32_H +#define KEEPASSX_TESTBASE32_H + +#include + +class Base32; + +class TestBase32 : public QObject +{ + Q_OBJECT + +private slots: + void testEncode(); + void testDecode(); + void testAddPadding(); + void testRemovePadding(); + void testSanitizeInput(); +}; + +#endif // KEEPASSX_TESTBASE32_H diff --git a/tests/TestEntry.cpp b/tests/TestEntry.cpp index 4d34cf31b..84ad03181 100644 --- a/tests/TestEntry.cpp +++ b/tests/TestEntry.cpp @@ -16,6 +16,7 @@ */ #include "TestEntry.h" +#include "config-keepassx-tests.h" #include @@ -130,3 +131,30 @@ void TestEntry::testClone() delete entryOrg; } + +void TestEntry::testResolveUrl() +{ + Entry* entry = new Entry(); + QString testUrl("www.google.com"); + QString testCmd("cmd://firefox " + testUrl); + QString testComplexCmd("cmd://firefox --start-now --url 'http://" + testUrl + "' --quit"); + QString nonHttpUrl("ftp://google.com"); + QString noUrl("random text inserted here"); + + // Test standard URL's + QCOMPARE(entry->resolveUrl(""), QString("")); + QCOMPARE(entry->resolveUrl(testUrl), "https://" + testUrl); + QCOMPARE(entry->resolveUrl("http://" + testUrl), "http://" + testUrl); + // Test cmd:// with no URL + QCOMPARE(entry->resolveUrl("cmd://firefox"), QString("")); + QCOMPARE(entry->resolveUrl("cmd://firefox --no-url"), QString("")); + // Test cmd:// with URL's + QCOMPARE(entry->resolveUrl(testCmd), "https://" + testUrl); + QCOMPARE(entry->resolveUrl(testComplexCmd), "http://" + testUrl); + // Test non-http URL + QCOMPARE(entry->resolveUrl(nonHttpUrl), QString("")); + // Test no URL + QCOMPARE(entry->resolveUrl(noUrl), QString("")); + + delete entry; +} diff --git a/tests/TestEntry.h b/tests/TestEntry.h index 0c97c0b9d..3f6d20ee3 100644 --- a/tests/TestEntry.h +++ b/tests/TestEntry.h @@ -31,6 +31,7 @@ private slots: void testHistoryItemDeletion(); void testCopyDataFrom(); void testClone(); + void testResolveUrl(); }; #endif // KEEPASSX_TESTENTRY_H diff --git a/tests/TestTotp.cpp b/tests/TestTotp.cpp index e22c2567e..48ff88144 100644 --- a/tests/TestTotp.cpp +++ b/tests/TestTotp.cpp @@ -18,15 +18,14 @@ #include "TestTotp.h" -#include -#include #include -#include +#include #include +#include +#include #include "crypto/Crypto.h" #include "totp/totp.h" -#include "totp/base32.h" QTEST_GUILESS_MAIN(TestTotp) @@ -35,12 +34,13 @@ void TestTotp::initTestCase() QVERIFY(Crypto::init()); } - void TestTotp::testParseSecret() { quint8 digits = 0; quint8 step = 0; - QString secret = "otpauth://totp/ACME%20Co:john@example.com?secret=HXDMVJECJJWSRB3HWIZR4IFUGFTMXBOZ&issuer=ACME%20Co&algorithm=SHA1&digits=6&period=30"; + QString secret = "otpauth://totp/" + "ACME%20Co:john@example.com?secret=HXDMVJECJJWSRB3HWIZR4IFUGFTMXBOZ&issuer=ACME%20Co&algorithm=" + "SHA1&digits=6&period=30"; QCOMPARE(QTotp::parseOtpString(secret, digits, step), QString("HXDMVJECJJWSRB3HWIZR4IFUGFTMXBOZ")); QCOMPARE(digits, quint8(6)); QCOMPARE(step, quint8(30)); @@ -60,25 +60,6 @@ void TestTotp::testParseSecret() QCOMPARE(step, quint8(30)); } -void TestTotp::testBase32() -{ - QByteArray key = QString("JBSW Y3DP EB3W 64TM MQXC 4LQA").toLatin1(); - QByteArray secret = Base32::base32_decode(key); - QCOMPARE(QString::fromLatin1(secret), QString("Hello world...")); - - key = QString("gezdgnbvgy3tqojqgezdgnbvgy3tqojq").toLatin1(); - secret = Base32::base32_decode(key); - QCOMPARE(QString::fromLatin1(secret), QString("12345678901234567890")); - - key = QString("ORSXG5A=").toLatin1(); - secret = Base32::base32_decode(key); - QCOMPARE(QString::fromLatin1(secret), QString("test")); - - key = QString("MZXW6YTBOI======").toLatin1(); - secret = Base32::base32_decode(key); - QCOMPARE(QString::fromLatin1(secret), QString("foobar")); -} - void TestTotp::testTotpCode() { // Test vectors from RFC 6238 diff --git a/tests/TestTotp.h b/tests/TestTotp.h index d197294dd..785a9f522 100644 --- a/tests/TestTotp.h +++ b/tests/TestTotp.h @@ -30,7 +30,6 @@ class TestTotp : public QObject private slots: void initTestCase(); void testParseSecret(); - void testBase32(); void testTotpCode(); };