mirror of
https://github.com/keepassxreboot/keepassxc.git
synced 2024-10-01 01:26:01 -04:00
Merge remote-tracking branch 'upstream/develop' into feature/import-csv-format
This commit is contained in:
commit
3fcf342fbc
5
.github/PULL_REQUEST_TEMPLATE.md
vendored
5
.github/PULL_REQUEST_TEMPLATE.md
vendored
@ -3,11 +3,11 @@
|
||||
## Description
|
||||
<!--- Describe your changes in detail -->
|
||||
|
||||
## Motivation and Context
|
||||
## Motivation and context
|
||||
<!--- Why is this change required? What problem does it solve? -->
|
||||
<!--- If it fixes an open issue, please link to the issue here. -->
|
||||
|
||||
## How Has This Been Tested?
|
||||
## How has this been tested?
|
||||
<!--- Please describe in detail how you tested your changes. -->
|
||||
<!--- Include details of your testing environment, and the tests you ran to -->
|
||||
<!--- see how your change affects other areas of the code, etc. -->
|
||||
@ -29,5 +29,6 @@
|
||||
- ✅ I have read the **CONTRIBUTING** document. **[REQUIRED]**
|
||||
- ✅ My code follows the code style of this project. **[REQUIRED]**
|
||||
- ✅ All new and existing tests passed. **[REQUIRED]**
|
||||
- ✅ I have compiled and verified my code with `-DWITH_ASAN=ON`. **[REQUIRED]**
|
||||
- ✅ My change requires a change to the documentation and I have updated it accordingly.
|
||||
- ✅ I have added tests to cover my changes.
|
||||
|
@ -13,15 +13,15 @@ compiler:
|
||||
- gcc
|
||||
|
||||
env:
|
||||
- CONFIG=Release
|
||||
- CONFIG=Debug
|
||||
- CONFIG=Release ASAN_OPTIONS=detect_odr_violation=1:leak_check_at_exit=0
|
||||
- CONFIG=Debug ASAN_OPTIONS=detect_odr_violation=1:leak_check_at_exit=0
|
||||
|
||||
git:
|
||||
depth: 3
|
||||
|
||||
before_install:
|
||||
- if [ "$TRAVIS_OS_NAME" = "linux" ]; then sudo apt-get -qq update; fi
|
||||
- if [ "$TRAVIS_OS_NAME" = "linux" ]; then sudo apt-get -qq install cmake libmicrohttpd10 libmicrohttpd-dev libxi-dev qtbase5-dev libqt5x11extras5-dev qttools5-dev qttools5-dev-tools libgcrypt20-dev zlib1g-dev libxtst-dev xvfb; fi
|
||||
- if [ "$TRAVIS_OS_NAME" = "linux" ]; then sudo apt-get -qq install cmake libclang-common-3.5-dev libxi-dev qtbase5-dev libqt5x11extras5-dev qttools5-dev qttools5-dev-tools libgcrypt20-dev zlib1g-dev libxtst-dev xvfb libyubikey-dev libykpers-1-dev; fi
|
||||
- if [ "$TRAVIS_OS_NAME" = "osx" ]; then brew update; fi
|
||||
- if [ "$TRAVIS_OS_NAME" = "osx" ]; then brew ls | grep -wq cmake || brew install cmake; fi
|
||||
- if [ "$TRAVIS_OS_NAME" = "osx" ]; then brew ls | grep -wq qt5 || brew install qt5; fi
|
||||
@ -32,7 +32,7 @@ before_script:
|
||||
- mkdir build && pushd build
|
||||
|
||||
script:
|
||||
- cmake -DCMAKE_BUILD_TYPE=${CONFIG} -DWITH_GUI_TESTS=ON -DWITH_XC_HTTP=ON -DWITH_XC_AUTOTYPE=ON -DWITH_XC_YUBIKEY=ON $CMAKE_ARGS ..
|
||||
- cmake -DCMAKE_BUILD_TYPE=${CONFIG} -DWITH_GUI_TESTS=ON -DWITH_ASAN=ON -DWITH_XC_HTTP=ON -DWITH_XC_AUTOTYPE=ON -DWITH_XC_YUBIKEY=ON $CMAKE_ARGS ..
|
||||
- make -j2
|
||||
- if [ "$TRAVIS_OS_NAME" = "linux" ]; then make test ARGS+="-E testgui --output-on-failure"; fi
|
||||
- if [ "$TRAVIS_OS_NAME" = "linux" ]; then xvfb-run -a --server-args="-screen 0 800x600x24" make test ARGS+="-R testgui --output-on-failure"; fi
|
||||
|
@ -32,11 +32,12 @@ include(CheckCXXSourceCompiles)
|
||||
option(WITH_TESTS "Enable building of unit tests" ON)
|
||||
option(WITH_GUI_TESTS "Enable building of GUI tests" OFF)
|
||||
option(WITH_DEV_BUILD "Use only for development. Disables/warns about deprecated methods." OFF)
|
||||
option(WITH_COVERAGE "Use to build with coverage tests. (GCC ONLY)." OFF)
|
||||
option(WITH_ASAN "Enable address sanitizer checks (Linux only)" OFF)
|
||||
option(WITH_COVERAGE "Use to build with coverage tests (GCC only)." OFF)
|
||||
|
||||
option(WITH_XC_AUTOTYPE "Include Auto-Type." ON)
|
||||
option(WITH_XC_HTTP "Include KeePassHTTP and Custom Icon Downloads." OFF)
|
||||
option(WITH_XC_YUBIKEY "Include Yubikey support." OFF)
|
||||
option(WITH_XC_YUBIKEY "Include YubiKey support." OFF)
|
||||
|
||||
set(KEEPASSXC_VERSION "2.1.3")
|
||||
set(KEEPASSXC_VERSION_NUM "2.1.3")
|
||||
@ -68,18 +69,35 @@ endmacro(add_gcc_compiler_flags)
|
||||
|
||||
add_definitions(-DQT_NO_EXCEPTIONS -DQT_STRICT_ITERATORS -DQT_NO_CAST_TO_ASCII)
|
||||
|
||||
add_gcc_compiler_flags("-fno-common -fstack-protector --param=ssp-buffer-size=4")
|
||||
add_gcc_compiler_flags("-fno-common")
|
||||
add_gcc_compiler_flags("-Wall -Wextra -Wundef -Wpointer-arith -Wno-long-long")
|
||||
add_gcc_compiler_flags("-Wformat=2 -Wmissing-format-attribute")
|
||||
add_gcc_compiler_flags("-fvisibility=hidden")
|
||||
add_gcc_compiler_cxxflags("-fvisibility-inlines-hidden")
|
||||
|
||||
if((CMAKE_COMPILER_IS_GNUCXX AND CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 4.8.999) OR CMAKE_COMPILER_IS_CLANGXX)
|
||||
add_gcc_compiler_flags("-fstack-protector-strong")
|
||||
else()
|
||||
add_gcc_compiler_flags("-fstack-protector --param=ssp-buffer-size=4")
|
||||
endif()
|
||||
|
||||
add_gcc_compiler_cxxflags("-fno-exceptions -fno-rtti")
|
||||
add_gcc_compiler_cxxflags("-Wnon-virtual-dtor -Wold-style-cast -Woverloaded-virtual")
|
||||
add_gcc_compiler_cflags("-Wchar-subscripts -Wwrite-strings")
|
||||
if(WITH_ASAN)
|
||||
if(NOT CMAKE_SYSTEM_NAME STREQUAL "Linux")
|
||||
message(FATAL_ERROR "WITH_ASAN is only supported on Linux at the moment.")
|
||||
endif()
|
||||
|
||||
add_gcc_compiler_flags("-fsanitize=address -DWITH_ASAN")
|
||||
|
||||
if(NOT (CMAKE_COMPILER_IS_GNUCXX AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4.9))
|
||||
add_gcc_compiler_flags("-fsanitize=leak -DWITH_LSAN")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
string(TOLOWER "${CMAKE_BUILD_TYPE}" CMAKE_BUILD_TYPE_LOWER)
|
||||
if (CMAKE_BUILD_TYPE_LOWER MATCHES (release|relwithdebinfo|minsizerel))
|
||||
if (CMAKE_BUILD_TYPE_LOWER MATCHES "(release|relwithdebinfo|minsizerel)")
|
||||
add_gcc_compiler_flags("-D_FORTIFY_SOURCE=2")
|
||||
endif()
|
||||
|
||||
@ -105,10 +123,14 @@ if(CMAKE_COMPILER_IS_GNUCC)
|
||||
endif()
|
||||
|
||||
if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
|
||||
if (CMAKE_COMPILER_IS_CLANGXX)
|
||||
add_gcc_compiler_flags("-Qunused-arguments")
|
||||
endif()
|
||||
add_gcc_compiler_flags("-pie -fPIE")
|
||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--no-add-needed -Wl,--as-needed -Wl,--no-undefined")
|
||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,-z,relro")
|
||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,-z,relro,-z,now")
|
||||
set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} -Wl,--no-add-needed -Wl,--as-needed")
|
||||
set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} -Wl,-z,relro")
|
||||
set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} -Wl,-z,relro,-z,now")
|
||||
endif()
|
||||
|
||||
add_gcc_compiler_cxxflags("-std=c++11")
|
||||
@ -127,6 +149,9 @@ if(MINGW)
|
||||
set(CMAKE_RC_COMPILER_INIT windres)
|
||||
enable_language(RC)
|
||||
set(CMAKE_RC_COMPILE_OBJECT "<CMAKE_RC_COMPILER> <FLAGS> -O coff <DEFINES> -i <SOURCE> -o <OBJECT>")
|
||||
# Enable DEP and ASLR
|
||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--nxcompat -Wl,--dynamicbase")
|
||||
set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} -Wl,--nxcompat -Wl,--dynamicbase")
|
||||
link_libraries(ws2_32 wsock32)
|
||||
endif()
|
||||
|
||||
@ -141,16 +166,19 @@ if(APPLE AND "${CMAKE_INSTALL_PREFIX}" STREQUAL "/usr/local")
|
||||
endif()
|
||||
|
||||
if(MINGW)
|
||||
set(CLI_INSTALL_DIR ".")
|
||||
set(BIN_INSTALL_DIR ".")
|
||||
set(PLUGIN_INSTALL_DIR ".")
|
||||
set(DATA_INSTALL_DIR "share")
|
||||
elseif(APPLE)
|
||||
set(CLI_INSTALL_DIR "/usr/local/bin")
|
||||
set(BIN_INSTALL_DIR ".")
|
||||
set(PLUGIN_INSTALL_DIR "${PROGNAME}.app/Contents/PlugIns")
|
||||
set(DATA_INSTALL_DIR "${PROGNAME}.app/Contents/Resources")
|
||||
else()
|
||||
include(GNUInstallDirs)
|
||||
|
||||
set(CLI_INSTALL_DIR "${CMAKE_INSTALL_BINDIR}")
|
||||
set(BIN_INSTALL_DIR "${CMAKE_INSTALL_BINDIR}")
|
||||
set(PLUGIN_INSTALL_DIR "${CMAKE_INSTALL_LIBDIR}/keepassxc")
|
||||
set(DATA_INSTALL_DIR "${CMAKE_INSTALL_DATADIR}/keepassxc")
|
||||
@ -194,6 +222,13 @@ if(NOT ZLIB_SUPPORTS_GZIP)
|
||||
message(FATAL_ERROR "zlib 1.2.x or higher is required to use the gzip format")
|
||||
endif()
|
||||
|
||||
# Optional
|
||||
if(WITH_XC_YUBIKEY)
|
||||
find_package(YubiKey REQUIRED)
|
||||
|
||||
include_directories(SYSTEM ${YUBIKEY_INCLUDE_DIRS})
|
||||
endif()
|
||||
|
||||
if(UNIX)
|
||||
check_cxx_source_compiles("#include <sys/prctl.h>
|
||||
int main() { prctl(PR_SET_DUMPABLE, 0); return 0; }"
|
||||
@ -222,7 +257,6 @@ include(FeatureSummary)
|
||||
|
||||
add_subdirectory(src)
|
||||
add_subdirectory(share)
|
||||
add_subdirectory(utils)
|
||||
if(WITH_TESTS)
|
||||
add_subdirectory(tests)
|
||||
endif(WITH_TESTS)
|
||||
|
21
README.md
21
README.md
@ -1,16 +1,16 @@
|
||||
# KeePassXC - KeePass Cross-platform Community Edition
|
||||
# KeePassXC [![Travis Build Status](https://travis-ci.org/keepassxreboot/keepassxc.svg?branch=develop)](https://travis-ci.org/keepassxreboot/keepassxc) [![Coverage Status](https://coveralls.io/repos/github/keepassxreboot/keepassxc/badge.svg)](https://coveralls.io/github/keepassxreboot/keepassxc) <a href='https://pledgie.com/campaigns/33487'><img alt='KeePassXC Authenticode Certificate Campaign!' align=right src='https://pledgie.com/campaigns/33487.png?skin_name=chrome' border='0'></a>
|
||||
|
||||
[![Travis Build Status](https://travis-ci.org/keepassxreboot/keepassxc.svg?branch=develop)](https://travis-ci.org/keepassxreboot/keepassxc) [![Coverage Status](https://coveralls.io/repos/github/keepassxreboot/keepassxc/badge.svg)](https://coveralls.io/github/keepassxreboot/keepassxc)
|
||||
<a href='https://pledgie.com/campaigns/33487'><img alt='KeePassXC Authenticode Certificate Campaign!' align=right src='https://pledgie.com/campaigns/33487.png?skin_name=chrome' border='0'></a>
|
||||
KeePass Cross-platform Community Edition
|
||||
|
||||
## About
|
||||
KeePassXC is a community fork of [KeePassX](https://www.keepassx.org/) with the goal to extend and improve it with new features and bugfixes to provide a feature-rich, fully cross-platform and modern open-source password manager.
|
||||
[KeePassXC](https://keepassxc.org) is a community fork of [KeePassX](https://www.keepassx.org/) with the goal to extend and improve it with new features and bugfixes to provide a feature-rich, fully cross-platform and modern open-source password manager.
|
||||
|
||||
|
||||
## Additional features compared to KeePassX
|
||||
- Auto-Type on all three major platforms (Linux, Windows, OS X)
|
||||
- Stand-alone password generator
|
||||
- Password strength meter
|
||||
- YubiKey HMAC-SHA1 authentication for unlocking databases
|
||||
- Using website favicons as entry icons
|
||||
- Merging of databases
|
||||
- Automatic reload when the database changed on disk
|
||||
@ -55,8 +55,19 @@ make -j8
|
||||
sudo make install
|
||||
```
|
||||
|
||||
To enable autotype, add `-DWITH_XC_AUTOTYPE=ON` to the `cmake` command. KeePassHTTP support is compiled in by adding `-DWITH_XC_HTTP=ON`. If these options are not specified, KeePassXC will be built without these plugins.
|
||||
cmake accepts the following options:
|
||||
|
||||
```
|
||||
-DWITH_XC_AUTOTYPE=[ON|OFF] Enable/Disable Auto-Type (default: ON)
|
||||
-DWITH_XC_HTTP=[ON|OFF] Enable/Disable KeePassHTTP and custom icon downloads (default: OFF)
|
||||
-DWITH_XC_YUBIKEY=[ON|OFF] Enable/Disable YubiKey HMAC-SHA1 authentication support (default: OFF)
|
||||
|
||||
-DWITH_TESTS=[ON|OFF] Enable/Disable building of unit tests (default: ON)
|
||||
-DWITH_GUI_TESTS=[ON|OFF] Enable/Disable building of GUI tests (default: OFF)
|
||||
-DWITH_DEV_BUILD=[ON|OFF] Enable/Disable deprecated method warnings (default: OFF)
|
||||
-DWITH_ASAN=[ON|OFF] Enable/Disable address sanitizer checks (Linux only) (default: OFF)
|
||||
-DWITH_COVERAGE=[ON|OFF] Enable/Disable coverage tests (GCC only) (default: OFF)
|
||||
```
|
||||
|
||||
### Contributing
|
||||
|
||||
|
27
cmake/FindYubiKey.cmake
Normal file
27
cmake/FindYubiKey.cmake
Normal file
@ -0,0 +1,27 @@
|
||||
# Copyright (C) 2014 Kyle Manna <kyle@kylemanna.com>
|
||||
#
|
||||
# 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 <http://www.gnu.org/licenses/>.
|
||||
|
||||
find_path(YUBIKEY_CORE_INCLUDE_DIR yubikey.h)
|
||||
find_path(YUBIKEY_PERS_INCLUDE_DIR ykcore.h PATH_SUFFIXES ykpers-1)
|
||||
set(YUBIKEY_INCLUDE_DIRS ${YUBIKEY_CORE_INCLUDE_DIR} ${YUBIKEY_PERS_INCLUDE_DIR})
|
||||
|
||||
find_library(YUBIKEY_CORE_LIBRARY yubikey)
|
||||
find_library(YUBIKEY_PERS_LIBRARY ykpers-1)
|
||||
set(YUBIKEY_LIBRARIES ${YUBIKEY_CORE_LIBRARY} ${YUBIKEY_PERS_LIBRARY})
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
find_package_handle_standard_args(YubiKey DEFAULT_MSG YUBIKEY_LIBRARIES YUBIKEY_INCLUDE_DIRS)
|
||||
|
||||
mark_as_advanced(YUBIKEY_LIBRARIES YUBIKEY_INCLUDE_DIRS)
|
@ -37,7 +37,7 @@ DOCKER_CONTAINER_NAME="keepassxc-build-container"
|
||||
CMAKE_OPTIONS=""
|
||||
COMPILER="g++"
|
||||
MAKE_OPTIONS="-j8"
|
||||
BUILD_PLUGINS="autotype http"
|
||||
BUILD_PLUGINS="autotype http yubikey"
|
||||
INSTALL_PREFIX="/usr/local"
|
||||
BUILD_SOURCE_TARBALL=true
|
||||
ORIG_BRANCH=""
|
||||
|
@ -119,9 +119,11 @@ set(keepassx_SOURCES
|
||||
gui/group/GroupView.cpp
|
||||
keys/CompositeKey.cpp
|
||||
keys/CompositeKey_p.h
|
||||
keys/drivers/YubiKey.h
|
||||
keys/FileKey.cpp
|
||||
keys/Key.h
|
||||
keys/PasswordKey.cpp
|
||||
keys/YkChallengeResponseKey.cpp
|
||||
streams/HashedBlockStream.cpp
|
||||
streams/LayeredStream.cpp
|
||||
streams/qtiocompressor.cpp
|
||||
@ -157,8 +159,9 @@ set(keepassx_FORMS
|
||||
gui/group/EditGroupWidgetMain.ui
|
||||
)
|
||||
|
||||
add_feature_info(KeePassHTTP WITH_XC_HTTP "KeePassHTTP support for ChromeIPass and PassIFox")
|
||||
add_feature_info(Autotype WITH_XC_AUTOTYPE "Auto-type passwords in Input fields")
|
||||
add_feature_info(AutoType WITH_XC_AUTOTYPE "Automatic password typing")
|
||||
add_feature_info(KeePassHTTP WITH_XC_HTTP "Browser integration compatible with ChromeIPass and PassIFox")
|
||||
add_feature_info(YubiKey WITH_XC_YUBIKEY "YubiKey HMAC-SHA1 challenge-response")
|
||||
|
||||
add_subdirectory(http)
|
||||
if(WITH_XC_HTTP)
|
||||
@ -166,6 +169,7 @@ if(WITH_XC_HTTP)
|
||||
endif()
|
||||
|
||||
add_subdirectory(autotype)
|
||||
add_subdirectory(cli)
|
||||
|
||||
set(autotype_SOURCES
|
||||
core/Tools.cpp
|
||||
@ -186,6 +190,12 @@ if(MINGW)
|
||||
${CMAKE_SOURCE_DIR}/share/windows/icon.rc)
|
||||
endif()
|
||||
|
||||
if(WITH_XC_YUBIKEY)
|
||||
set(keepassx_SOURCES ${keepassx_SOURCES} keys/drivers/YubiKey.cpp)
|
||||
else()
|
||||
set(keepassx_SOURCES ${keepassx_SOURCES} keys/drivers/YubiKeyStub.cpp)
|
||||
endif()
|
||||
|
||||
qt5_wrap_ui(keepassx_SOURCES ${keepassx_FORMS})
|
||||
|
||||
add_library(zxcvbn STATIC zxcvbn/zxcvbn.cpp)
|
||||
@ -202,6 +212,7 @@ set_target_properties(keepassx_core PROPERTIES COMPILE_DEFINITIONS KEEPASSX_BUIL
|
||||
target_link_libraries(keepassx_core
|
||||
${keepasshttp_LIB}
|
||||
${autotype_LIB}
|
||||
${YUBIKEY_LIBRARIES}
|
||||
zxcvbn
|
||||
Qt5::Core
|
||||
Qt5::Concurrent
|
||||
|
@ -48,13 +48,13 @@ public:
|
||||
static AutoType* instance();
|
||||
static void createTestInstance();
|
||||
|
||||
public Q_SLOTS:
|
||||
public slots:
|
||||
void performGlobalAutoType(const QList<Database*>& dbList);
|
||||
|
||||
Q_SIGNALS:
|
||||
signals:
|
||||
void globalShortcutTriggered();
|
||||
|
||||
private Q_SLOTS:
|
||||
private slots:
|
||||
void performAutoTypeFromGlobal(Entry* entry, const QString& sequence);
|
||||
void resetInAutoType();
|
||||
void unloadPlugin();
|
||||
|
@ -91,7 +91,7 @@ void AutoTypeSelectDialog::emitEntryActivated(const QModelIndex& index)
|
||||
|
||||
Entry* entry = m_view->entryFromIndex(index);
|
||||
accept();
|
||||
Q_EMIT entryActivated(entry, m_sequences[entry]);
|
||||
emit entryActivated(entry, m_sequences[entry]);
|
||||
}
|
||||
|
||||
void AutoTypeSelectDialog::entryRemoved()
|
||||
|
@ -33,13 +33,13 @@ public:
|
||||
explicit AutoTypeSelectDialog(QWidget* parent = nullptr);
|
||||
void setEntries(const QList<Entry*>& entries, const QHash<Entry*, QString>& sequences);
|
||||
|
||||
Q_SIGNALS:
|
||||
signals:
|
||||
void entryActivated(Entry* entry, const QString& sequence);
|
||||
|
||||
public Q_SLOTS:
|
||||
public slots:
|
||||
void done(int r) override;
|
||||
|
||||
private Q_SLOTS:
|
||||
private slots:
|
||||
void emitEntryActivated(const QModelIndex& index);
|
||||
void entryRemoved();
|
||||
|
||||
|
@ -32,7 +32,7 @@ public:
|
||||
protected:
|
||||
void mouseMoveEvent(QMouseEvent* event) override;
|
||||
|
||||
private Q_SLOTS:
|
||||
private slots:
|
||||
void selectFirstEntry();
|
||||
};
|
||||
|
||||
|
@ -460,7 +460,7 @@ OSStatus AutoTypePlatformMac::hotkeyHandler(EventHandlerCallRef nextHandler, Eve
|
||||
|
||||
if (::GetEventParameter(theEvent, kEventParamDirectObject, typeEventHotKeyID, nullptr, sizeof(hotkeyId), nullptr, &hotkeyId) == noErr
|
||||
&& hotkeyId.id == HOTKEY_ID) {
|
||||
Q_EMIT self->globalShortcutTriggered();
|
||||
emit self->globalShortcutTriggered();
|
||||
}
|
||||
|
||||
return noErr;
|
||||
|
@ -51,7 +51,7 @@ public:
|
||||
void sendChar(const QChar& ch, bool isKeyDown);
|
||||
void sendKey(Qt::Key key, bool isKeyDown);
|
||||
|
||||
Q_SIGNALS:
|
||||
signals:
|
||||
void globalShortcutTriggered();
|
||||
|
||||
private:
|
||||
|
@ -60,7 +60,7 @@ public:
|
||||
void addActionChar(AutoTypeChar* action);
|
||||
void addActionKey(AutoTypeKey* action);
|
||||
|
||||
Q_SIGNALS:
|
||||
signals:
|
||||
void globalShortcutTriggered();
|
||||
|
||||
private:
|
||||
|
@ -96,7 +96,7 @@ int AutoTypePlatformWin::platformEventFilter(void* event)
|
||||
MSG *msg = static_cast<MSG *>(event);
|
||||
|
||||
if (msg->message == WM_HOTKEY && msg->wParam == HOTKEY_ID) {
|
||||
Q_EMIT globalShortcutTriggered();
|
||||
emit globalShortcutTriggered();
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@ -45,7 +45,7 @@ public:
|
||||
void sendChar(const QChar& ch, bool isKeyDown);
|
||||
void sendKey(Qt::Key key, bool isKeyDown);
|
||||
|
||||
Q_SIGNALS:
|
||||
signals:
|
||||
void globalShortcutTriggered();
|
||||
|
||||
private:
|
||||
|
@ -214,7 +214,7 @@ int AutoTypePlatformX11::platformEventFilter(void* event)
|
||||
&& (!QApplication::activeWindow() || QApplication::activeWindow()->isMinimized())
|
||||
&& m_loaded) {
|
||||
if (type == XCB_KEY_PRESS) {
|
||||
Q_EMIT globalShortcutTriggered();
|
||||
emit globalShortcutTriggered();
|
||||
}
|
||||
|
||||
return 1;
|
||||
|
@ -59,7 +59,7 @@ public:
|
||||
|
||||
void SendKeyPressedEvent(KeySym keysym);
|
||||
|
||||
Q_SIGNALS:
|
||||
signals:
|
||||
void globalShortcutTriggered();
|
||||
|
||||
private:
|
||||
|
@ -1,4 +1,4 @@
|
||||
# Copyright (C) 2010 Felix Geyer <debfx@fobos.de>
|
||||
# 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
|
||||
@ -13,24 +13,31 @@
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
include_directories(../src)
|
||||
set(cli_SOURCES
|
||||
EntropyMeter.cpp
|
||||
EntropyMeter.h
|
||||
Extract.cpp
|
||||
Extract.h
|
||||
List.cpp
|
||||
List.h
|
||||
Merge.cpp
|
||||
Merge.h
|
||||
Show.cpp
|
||||
Show.h)
|
||||
|
||||
add_executable(kdbx-extract kdbx-extract.cpp)
|
||||
target_link_libraries(kdbx-extract
|
||||
add_library(cli STATIC ${cli_SOURCES})
|
||||
target_link_libraries(cli Qt5::Core Qt5::Widgets)
|
||||
|
||||
add_executable(keepassxc-cli keepassxc-cli.cpp)
|
||||
target_link_libraries(keepassxc-cli
|
||||
cli
|
||||
keepassx_core
|
||||
Qt5::Core
|
||||
${GCRYPT_LIBRARIES}
|
||||
${GPGERROR_LIBRARIES}
|
||||
${ZLIB_LIBRARIES})
|
||||
${ZLIB_LIBRARIES}
|
||||
zxcvbn)
|
||||
|
||||
add_executable(kdbx-merge kdbx-merge.cpp)
|
||||
target_link_libraries(kdbx-merge
|
||||
keepassx_core
|
||||
Qt5::Core
|
||||
${GCRYPT_LIBRARIES}
|
||||
${GPGERROR_LIBRARIES}
|
||||
${ZLIB_LIBRARIES})
|
||||
|
||||
|
||||
add_executable(entropy-meter entropy-meter.cpp)
|
||||
target_link_libraries(entropy-meter zxcvbn)
|
||||
install(TARGETS keepassxc-cli
|
||||
BUNDLE DESTINATION . COMPONENT Runtime
|
||||
RUNTIME DESTINATION ${CLI_INSTALL_DIR} COMPONENT Runtime)
|
@ -6,6 +6,8 @@ Copyright (c) 2016, KeePassXC Team
|
||||
See zxcvbn/zxcvbn.cpp for complete COPYRIGHT Notice
|
||||
*/
|
||||
|
||||
#include "EntropyMeter.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
@ -76,7 +78,7 @@ static void calculate(const char *pwd, int advanced)
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
int EntropyMeter::execute(int argc, char **argv)
|
||||
{
|
||||
printf("KeePassXC Entropy Meter, based on zxcvbn-c.\nEnter your password below or pass it as argv\n");
|
||||
printf(" Usage: entropy-meter [-a] [pwd1 pwd2 ...]\n> ");
|
27
src/cli/EntropyMeter.h
Normal file
27
src/cli/EntropyMeter.h
Normal file
@ -0,0 +1,27 @@
|
||||
/*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef KEEPASSXC_ENTROPYMETER_H
|
||||
#define KEEPASSXC_ENTROPYMETER_H
|
||||
|
||||
class EntropyMeter
|
||||
{
|
||||
public:
|
||||
static int execute(int argc, char** argv);
|
||||
};
|
||||
|
||||
#endif // KEEPASSXC_ENTROPYMETER_H
|
@ -15,8 +15,11 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <cstdlib>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "Extract.h"
|
||||
|
||||
#include <QCommandLineParser>
|
||||
#include <QCoreApplication>
|
||||
#include <QFile>
|
||||
@ -24,32 +27,28 @@
|
||||
#include <QTextStream>
|
||||
|
||||
#include "core/Database.h"
|
||||
#include "crypto/Crypto.h"
|
||||
#include "format/KeePass2Reader.h"
|
||||
#include "keys/CompositeKey.h"
|
||||
#include "keys/FileKey.h"
|
||||
#include "keys/PasswordKey.h"
|
||||
|
||||
int main(int argc, char **argv)
|
||||
int Extract::execute(int argc, char **argv)
|
||||
{
|
||||
QCoreApplication app(argc, argv);
|
||||
QTextStream out(stdout);
|
||||
|
||||
QCommandLineParser parser;
|
||||
parser.setApplicationDescription(QCoreApplication::translate("main",
|
||||
"Extract and print a KeePassXC database file."));
|
||||
parser.addPositionalArgument("database", QCoreApplication::translate("main", "path of the database to extract."));
|
||||
parser.addHelpOption();
|
||||
"Extract and print the content of a database."));
|
||||
parser.addPositionalArgument("database", QCoreApplication::translate("main", "Path of the database to extract."));
|
||||
parser.process(app);
|
||||
|
||||
const QStringList args = parser.positionalArguments();
|
||||
if (args.size() != 1) {
|
||||
parser.showHelp();
|
||||
return 1;
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
if (!Crypto::init()) {
|
||||
qFatal("Fatal error while testing the cryptographic functions:\n%s", qPrintable(Crypto::errorString()));
|
||||
}
|
||||
out << "Insert the database password\n> ";
|
||||
out.flush();
|
||||
|
||||
static QTextStream inputTextStream(stdin, QIODevice::ReadOnly);
|
||||
QString line = inputTextStream.readLine();
|
||||
@ -59,11 +58,11 @@ int main(int argc, char **argv)
|
||||
QFile dbFile(databaseFilename);
|
||||
if (!dbFile.exists()) {
|
||||
qCritical("File %s does not exist.", qPrintable(databaseFilename));
|
||||
return 1;
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
if (!dbFile.open(QIODevice::ReadOnly)) {
|
||||
qCritical("Unable to open file %s.", qPrintable(databaseFilename));
|
||||
return 1;
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
KeePass2Reader reader;
|
||||
@ -76,15 +75,14 @@ int main(int argc, char **argv)
|
||||
if (reader.hasError()) {
|
||||
if (xmlData.isEmpty()) {
|
||||
qCritical("Error while reading the database:\n%s", qPrintable(reader.errorString()));
|
||||
return 1;
|
||||
}
|
||||
else {
|
||||
qWarning("Error while parsing the database:\n%s\n", qPrintable(reader.errorString()));
|
||||
}
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
QTextStream out(stdout);
|
||||
out << xmlData.constData() << "\n";
|
||||
|
||||
return 0;
|
||||
return EXIT_SUCCESS;
|
||||
}
|
27
src/cli/Extract.h
Normal file
27
src/cli/Extract.h
Normal file
@ -0,0 +1,27 @@
|
||||
/*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef KEEPASSXC_EXTRACT_H
|
||||
#define KEEPASSXC_EXTRACT_H
|
||||
|
||||
class Extract
|
||||
{
|
||||
public:
|
||||
static int execute(int argc, char** argv);
|
||||
};
|
||||
|
||||
#endif // KEEPASSXC_EXTRACT_H
|
89
src/cli/List.cpp
Normal file
89
src/cli/List.cpp
Normal file
@ -0,0 +1,89 @@
|
||||
/*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <cstdlib>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "List.h"
|
||||
|
||||
#include <QCommandLineParser>
|
||||
#include <QCoreApplication>
|
||||
#include <QStringList>
|
||||
#include <QTextStream>
|
||||
|
||||
#include "core/Database.h"
|
||||
#include "core/Entry.h"
|
||||
#include "core/Group.h"
|
||||
#include "keys/CompositeKey.h"
|
||||
|
||||
void printGroup(Group* group, QString baseName, int depth) {
|
||||
|
||||
QTextStream out(stdout);
|
||||
|
||||
QString groupName = baseName + group->name() + "/";
|
||||
QString indentation = QString(" ").repeated(depth);
|
||||
|
||||
out << indentation << groupName << " " << group->uuid().toHex() << "\n";
|
||||
out.flush();
|
||||
|
||||
if (group->entries().isEmpty() && group->children().isEmpty()) {
|
||||
out << indentation << " [empty]\n";
|
||||
return;
|
||||
}
|
||||
|
||||
for (Entry* entry : group->entries()) {
|
||||
out << indentation << " " << entry->title() << " " << entry->uuid().toHex() << "\n";
|
||||
}
|
||||
|
||||
for (Group* innerGroup : group->children()) {
|
||||
printGroup(innerGroup, groupName, depth + 1);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
int List::execute(int argc, char **argv)
|
||||
{
|
||||
QCoreApplication app(argc, argv);
|
||||
QTextStream out(stdout);
|
||||
|
||||
QCommandLineParser parser;
|
||||
parser.setApplicationDescription(QCoreApplication::translate("main",
|
||||
"List database entries."));
|
||||
parser.addPositionalArgument("database", QCoreApplication::translate("main", "Path of the database."));
|
||||
parser.process(app);
|
||||
|
||||
const QStringList args = parser.positionalArguments();
|
||||
if (args.size() != 1) {
|
||||
parser.showHelp();
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
out << "Insert the database password\n> ";
|
||||
out.flush();
|
||||
|
||||
static QTextStream inputTextStream(stdin, QIODevice::ReadOnly);
|
||||
QString line = inputTextStream.readLine();
|
||||
CompositeKey key = CompositeKey::readFromLine(line);
|
||||
|
||||
Database* db = Database::openDatabaseFile(args.at(0), key);
|
||||
if (db == nullptr) {
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
printGroup(db->rootGroup(), QString(""), 0);
|
||||
return EXIT_SUCCESS;
|
||||
}
|
27
src/cli/List.h
Normal file
27
src/cli/List.h
Normal file
@ -0,0 +1,27 @@
|
||||
/*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef KEEPASSXC_LIST_H
|
||||
#define KEEPASSXC_LIST_H
|
||||
|
||||
class List
|
||||
{
|
||||
public:
|
||||
static int execute(int argc, char** argv);
|
||||
};
|
||||
|
||||
#endif // KEEPASSXC_LIST_H
|
@ -15,50 +15,47 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <cstdlib>
|
||||
|
||||
#include "Merge.h"
|
||||
|
||||
#include <QCommandLineParser>
|
||||
#include <QCoreApplication>
|
||||
#include <QFile>
|
||||
#include <QSaveFile>
|
||||
#include <QStringList>
|
||||
#include <QTextStream>
|
||||
|
||||
#include "core/Database.h"
|
||||
#include "crypto/Crypto.h"
|
||||
#include "format/KeePass2Reader.h"
|
||||
#include "format/KeePass2Writer.h"
|
||||
#include "keys/CompositeKey.h"
|
||||
|
||||
int main(int argc, char **argv)
|
||||
int Merge::execute(int argc, char** argv)
|
||||
{
|
||||
|
||||
QCoreApplication app(argc, argv);
|
||||
QTextStream out(stdout);
|
||||
|
||||
QCommandLineParser parser;
|
||||
parser.setApplicationDescription(QCoreApplication::translate("main", "Merge 2 KeePassXC database files."));
|
||||
parser.addPositionalArgument("database1", QCoreApplication::translate("main", "path of the database to merge into."));
|
||||
parser.addPositionalArgument("database2", QCoreApplication::translate("main", "path of the database to merge from."));
|
||||
parser.setApplicationDescription(QCoreApplication::translate("main", "Merge two databases."));
|
||||
parser.addPositionalArgument("database1", QCoreApplication::translate("main", "Path of the database to merge into."));
|
||||
parser.addPositionalArgument("database2", QCoreApplication::translate("main", "Path of the database to merge from."));
|
||||
|
||||
QCommandLineOption samePasswordOption(QStringList() << "s" << "same-password",
|
||||
QCoreApplication::translate("main", "use the same password for both database files."));
|
||||
QCoreApplication::translate("main", "Use the same password for both database files."));
|
||||
|
||||
parser.addHelpOption();
|
||||
parser.addOption(samePasswordOption);
|
||||
parser.process(app);
|
||||
|
||||
const QStringList args = parser.positionalArguments();
|
||||
if (args.size() != 2) {
|
||||
parser.showHelp();
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!Crypto::init()) {
|
||||
qFatal("Fatal error while testing the cryptographic functions:\n%s", qPrintable(Crypto::errorString()));
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
out << "Insert the first database password\n> ";
|
||||
out.flush();
|
||||
|
||||
static QTextStream inputTextStream(stdin, QIODevice::ReadOnly);
|
||||
|
||||
QString line1 = inputTextStream.readLine();
|
||||
CompositeKey key1 = CompositeKey::readFromLine(line1);
|
||||
|
||||
@ -67,56 +64,29 @@ int main(int argc, char **argv)
|
||||
key2 = *key1.clone();
|
||||
}
|
||||
else {
|
||||
out << "Insert the second database password\n> ";
|
||||
out.flush();
|
||||
QString line2 = inputTextStream.readLine();
|
||||
key2 = CompositeKey::readFromLine(line2);
|
||||
}
|
||||
|
||||
|
||||
QString databaseFilename1 = args.at(0);
|
||||
QFile dbFile1(databaseFilename1);
|
||||
if (!dbFile1.exists()) {
|
||||
qCritical("File %s does not exist.", qPrintable(databaseFilename1));
|
||||
return 1;
|
||||
}
|
||||
if (!dbFile1.open(QIODevice::ReadOnly)) {
|
||||
qCritical("Unable to open file %s.", qPrintable(databaseFilename1));
|
||||
return 1;
|
||||
Database* db1 = Database::openDatabaseFile(args.at(0), key1);
|
||||
if (db1 == nullptr) {
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
KeePass2Reader reader1;
|
||||
Database* db1 = reader1.readDatabase(&dbFile1, key1);
|
||||
|
||||
if (reader1.hasError()) {
|
||||
qCritical("Error while parsing the database:\n%s\n", qPrintable(reader1.errorString()));
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
QString databaseFilename2 = args.at(1);
|
||||
QFile dbFile2(databaseFilename2);
|
||||
if (!dbFile2.exists()) {
|
||||
qCritical("File %s does not exist.", qPrintable(databaseFilename2));
|
||||
return 1;
|
||||
}
|
||||
if (!dbFile2.open(QIODevice::ReadOnly)) {
|
||||
qCritical("Unable to open file %s.", qPrintable(databaseFilename2));
|
||||
return 1;
|
||||
}
|
||||
|
||||
KeePass2Reader reader2;
|
||||
Database* db2 = reader2.readDatabase(&dbFile2, key2);
|
||||
|
||||
if (reader2.hasError()) {
|
||||
qCritical("Error while parsing the database:\n%s\n", qPrintable(reader2.errorString()));
|
||||
return 1;
|
||||
Database* db2 = Database::openDatabaseFile(args.at(1), key2);
|
||||
if (db2 == nullptr) {
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
db1->merge(db2);
|
||||
|
||||
QSaveFile saveFile(databaseFilename1);
|
||||
QSaveFile saveFile(args.at(0));
|
||||
if (!saveFile.open(QIODevice::WriteOnly)) {
|
||||
qCritical("Unable to open file %s for writing.", qPrintable(databaseFilename1));
|
||||
return 1;
|
||||
qCritical("Unable to open file %s for writing.", qPrintable(args.at(0)));
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
KeePass2Writer writer;
|
||||
@ -124,15 +94,15 @@ int main(int argc, char **argv)
|
||||
|
||||
if (writer.hasError()) {
|
||||
qCritical("Error while updating the database:\n%s\n", qPrintable(writer.errorString()));
|
||||
return 1;
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
if (!saveFile.commit()) {
|
||||
qCritical("Error while updating the database:\n%s\n", qPrintable(writer.errorString()));
|
||||
return 0;
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
qDebug("Successfully merged the database files.\n");
|
||||
return 1;
|
||||
out << "Successfully merged the database files.\n";
|
||||
return EXIT_SUCCESS;
|
||||
|
||||
}
|
27
src/cli/Merge.h
Normal file
27
src/cli/Merge.h
Normal file
@ -0,0 +1,27 @@
|
||||
/*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef KEEPASSXC_MERGE_H
|
||||
#define KEEPASSXC_MERGE_H
|
||||
|
||||
class Merge
|
||||
{
|
||||
public:
|
||||
static int execute(int argc, char** argv);
|
||||
};
|
||||
|
||||
#endif // KEEPASSXC_MERGE_H
|
72
src/cli/Show.cpp
Normal file
72
src/cli/Show.cpp
Normal file
@ -0,0 +1,72 @@
|
||||
/*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <cstdlib>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "Show.h"
|
||||
|
||||
#include <QCommandLineParser>
|
||||
#include <QCoreApplication>
|
||||
#include <QStringList>
|
||||
#include <QTextStream>
|
||||
|
||||
#include "core/Database.h"
|
||||
#include "core/Entry.h"
|
||||
#include "core/Group.h"
|
||||
#include "keys/CompositeKey.h"
|
||||
|
||||
int Show::execute(int argc, char **argv)
|
||||
{
|
||||
QCoreApplication app(argc, argv);
|
||||
QTextStream out(stdout);
|
||||
|
||||
QCommandLineParser parser;
|
||||
parser.setApplicationDescription(QCoreApplication::translate("main",
|
||||
"Show a password."));
|
||||
parser.addPositionalArgument("database", QCoreApplication::translate("main", "Path of the database."));
|
||||
parser.addPositionalArgument("uuid", QCoreApplication::translate("main", "Uuid of the entry to show"));
|
||||
parser.process(app);
|
||||
|
||||
const QStringList args = parser.positionalArguments();
|
||||
if (args.size() != 2) {
|
||||
parser.showHelp();
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
out << "Insert the database password\n> ";
|
||||
out.flush();
|
||||
|
||||
static QTextStream inputTextStream(stdin, QIODevice::ReadOnly);
|
||||
QString line = inputTextStream.readLine();
|
||||
CompositeKey key = CompositeKey::readFromLine(line);
|
||||
|
||||
Database* db = Database::openDatabaseFile(args.at(0), key);
|
||||
if (db == nullptr) {
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
Uuid uuid = Uuid::fromHex(args.at(1));
|
||||
Entry* entry = db->resolveEntry(uuid);
|
||||
if (entry == nullptr) {
|
||||
qCritical("No entry found with uuid %s", qPrintable(uuid.toHex()));
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
out << entry->password() << "\n";
|
||||
return EXIT_SUCCESS;
|
||||
}
|
27
src/cli/Show.h
Normal file
27
src/cli/Show.h
Normal file
@ -0,0 +1,27 @@
|
||||
/*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef KEEPASSXC_SHOW_H
|
||||
#define KEEPASSXC_SHOW_H
|
||||
|
||||
class Show
|
||||
{
|
||||
public:
|
||||
static int execute(int argc, char** argv);
|
||||
};
|
||||
|
||||
#endif // KEEPASSXC_SHOW_H
|
114
src/cli/keepassxc-cli.cpp
Normal file
114
src/cli/keepassxc-cli.cpp
Normal file
@ -0,0 +1,114 @@
|
||||
/*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <cstdlib>
|
||||
|
||||
#include <QCommandLineParser>
|
||||
#include <QCoreApplication>
|
||||
#include <QStringList>
|
||||
|
||||
#include <cli/EntropyMeter.h>
|
||||
#include <cli/Extract.h>
|
||||
#include <cli/List.h>
|
||||
#include <cli/Merge.h>
|
||||
#include <cli/Show.h>
|
||||
|
||||
#include "config-keepassx.h"
|
||||
#include "core/Tools.h"
|
||||
#include "crypto/Crypto.h"
|
||||
|
||||
#if defined(WITH_ASAN) && defined(WITH_LSAN)
|
||||
#include <sanitizer/lsan_interface.h>
|
||||
#endif
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
#ifdef QT_NO_DEBUG
|
||||
Tools::disableCoreDumps();
|
||||
#endif
|
||||
|
||||
if (!Crypto::init()) {
|
||||
qFatal("Fatal error while testing the cryptographic functions:\n%s", qPrintable(Crypto::errorString()));
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
QCoreApplication app(argc, argv);
|
||||
app.setApplicationVersion(KEEPASSX_VERSION);
|
||||
|
||||
QCommandLineParser parser;
|
||||
|
||||
QString description("KeePassXC command line interface.");
|
||||
description = description.append(QString("\n\nAvailable commands:"));
|
||||
description = description.append(QString("\n extract\tExtract and print the content of a database."));
|
||||
description = description.append(QString("\n entropy-meter\tCalculate password entropy."));
|
||||
description = description.append(QString("\n list\t\tList database entries."));
|
||||
description = description.append(QString("\n merge\t\tMerge two databases."));
|
||||
description = description.append(QString("\n show\t\tShow a password."));
|
||||
parser.setApplicationDescription(QCoreApplication::translate("main", qPrintable(description)));
|
||||
|
||||
parser.addPositionalArgument("command", QCoreApplication::translate("main", "Name of the command to execute."));
|
||||
|
||||
parser.addHelpOption();
|
||||
parser.addVersionOption();
|
||||
// TODO : use process once the setOptionsAfterPositionalArgumentsMode (Qt 5.6)
|
||||
// is available. Until then, options passed to sub-commands won't be
|
||||
// recognized by this parser.
|
||||
// parser.process(app);
|
||||
|
||||
if (argc < 2) {
|
||||
parser.showHelp();
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
QString commandName = argv[1];
|
||||
|
||||
// Removing the first cli argument before dispatching.
|
||||
++argv;
|
||||
--argc;
|
||||
|
||||
int exitCode = EXIT_FAILURE;
|
||||
|
||||
if (commandName == "entropy-meter") {
|
||||
argv[0] = const_cast<char*>("keepassxc-cli entropy-meter");
|
||||
exitCode = EntropyMeter::execute(argc, argv);
|
||||
} else if (commandName == "extract") {
|
||||
argv[0] = const_cast<char*>("keepassxc-cli extract");
|
||||
exitCode = Extract::execute(argc, argv);
|
||||
} else if (commandName == "list") {
|
||||
argv[0] = const_cast<char*>("keepassxc-cli list");
|
||||
exitCode = List::execute(argc, argv);
|
||||
} else if (commandName == "merge") {
|
||||
argv[0] = const_cast<char*>("keepassxc-cli merge");
|
||||
exitCode = Merge::execute(argc, argv);
|
||||
} else if (commandName == "show") {
|
||||
argv[0] = const_cast<char*>("keepassxc-cli show");
|
||||
exitCode = Show::execute(argc, argv);
|
||||
} else {
|
||||
qCritical("Invalid command %s.", qPrintable(commandName));
|
||||
parser.showHelp();
|
||||
exitCode = EXIT_FAILURE;
|
||||
}
|
||||
|
||||
#if defined(WITH_ASAN) && defined(WITH_LSAN)
|
||||
// do leak check here to prevent massive tail of end-of-process leak errors from third-party libraries
|
||||
__lsan_do_leak_check();
|
||||
__lsan_disable();
|
||||
#endif
|
||||
|
||||
return exitCode;
|
||||
|
||||
}
|
@ -39,29 +39,29 @@ void AutoTypeAssociations::copyDataFrom(const AutoTypeAssociations* other)
|
||||
return;
|
||||
}
|
||||
|
||||
Q_EMIT aboutToReset();
|
||||
emit aboutToReset();
|
||||
m_associations = other->m_associations;
|
||||
Q_EMIT reset();
|
||||
Q_EMIT modified();
|
||||
emit reset();
|
||||
emit modified();
|
||||
}
|
||||
|
||||
void AutoTypeAssociations::add(const AutoTypeAssociations::Association& association)
|
||||
{
|
||||
int index = m_associations.size();
|
||||
Q_EMIT aboutToAdd(index);
|
||||
emit aboutToAdd(index);
|
||||
m_associations.append(association);
|
||||
Q_EMIT added(index);
|
||||
Q_EMIT modified();
|
||||
emit added(index);
|
||||
emit modified();
|
||||
}
|
||||
|
||||
void AutoTypeAssociations::remove(int index)
|
||||
{
|
||||
Q_ASSERT(index >= 0 && index < m_associations.size());
|
||||
|
||||
Q_EMIT aboutToRemove(index);
|
||||
emit aboutToRemove(index);
|
||||
m_associations.removeAt(index);
|
||||
Q_EMIT removed(index);
|
||||
Q_EMIT modified();
|
||||
emit removed(index);
|
||||
emit modified();
|
||||
}
|
||||
|
||||
void AutoTypeAssociations::removeEmpty()
|
||||
@ -81,8 +81,8 @@ void AutoTypeAssociations::update(int index, const AutoTypeAssociations::Associa
|
||||
|
||||
if (m_associations.at(index) != association) {
|
||||
m_associations[index] = association;
|
||||
Q_EMIT dataChanged(index);
|
||||
Q_EMIT modified();
|
||||
emit dataChanged(index);
|
||||
emit modified();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -48,7 +48,7 @@ public:
|
||||
private:
|
||||
QList<AutoTypeAssociations::Association> m_associations;
|
||||
|
||||
Q_SIGNALS:
|
||||
signals:
|
||||
void modified();
|
||||
void dataChanged(int index);
|
||||
void aboutToAdd(int index);
|
||||
|
@ -25,6 +25,7 @@
|
||||
#include "core/Metadata.h"
|
||||
#include "crypto/Random.h"
|
||||
#include "format/KeePass2.h"
|
||||
#include "format/KeePass2Reader.h"
|
||||
|
||||
QHash<Uuid, Database*> Database::m_uuidMap;
|
||||
|
||||
@ -176,6 +177,17 @@ QByteArray Database::transformedMasterKey() const
|
||||
return m_data.transformedMasterKey;
|
||||
}
|
||||
|
||||
QByteArray Database::challengeResponseKey() const
|
||||
{
|
||||
return m_data.challengeResponseKey;
|
||||
}
|
||||
|
||||
bool Database::challengeMasterSeed(const QByteArray& masterSeed)
|
||||
{
|
||||
m_data.masterSeed = masterSeed;
|
||||
return m_data.key.challenge(masterSeed, m_data.challengeResponseKey);
|
||||
}
|
||||
|
||||
void Database::setCipher(const Uuid& cipher)
|
||||
{
|
||||
Q_ASSERT(!cipher.isNull());
|
||||
@ -227,7 +239,7 @@ bool Database::setKey(const CompositeKey& key, const QByteArray& transformSeed,
|
||||
if (updateChangedTime) {
|
||||
m_metadata->setMasterKeyChanged(QDateTime::currentDateTimeUtc());
|
||||
}
|
||||
Q_EMIT modifiedImmediate();
|
||||
emit modifiedImmediate();
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -246,6 +258,20 @@ bool Database::verifyKey(const CompositeKey& key) const
|
||||
{
|
||||
Q_ASSERT(hasKey());
|
||||
|
||||
if (!m_data.challengeResponseKey.isEmpty()) {
|
||||
QByteArray result;
|
||||
|
||||
if (!key.challenge(m_data.masterSeed, result)) {
|
||||
// challenge failed, (YubiKey?) removed?
|
||||
return false;
|
||||
}
|
||||
|
||||
if (m_data.challengeResponseKey != result) {
|
||||
// wrong response from challenged device(s)
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return (m_data.key.rawKey() == key.rawKey());
|
||||
}
|
||||
|
||||
@ -285,7 +311,7 @@ void Database::recycleGroup(Group* group)
|
||||
void Database::merge(const Database* other)
|
||||
{
|
||||
m_rootGroup->merge(other->rootGroup());
|
||||
Q_EMIT modified();
|
||||
emit modified();
|
||||
}
|
||||
|
||||
void Database::setEmitModified(bool value)
|
||||
@ -330,3 +356,27 @@ const CompositeKey & Database::key() const
|
||||
return m_data.key;
|
||||
}
|
||||
|
||||
Database* Database::openDatabaseFile(QString fileName, CompositeKey key)
|
||||
{
|
||||
|
||||
QFile dbFile(fileName);
|
||||
if (!dbFile.exists()) {
|
||||
qCritical("File %s does not exist.", qPrintable(fileName));
|
||||
return nullptr;
|
||||
}
|
||||
if (!dbFile.open(QIODevice::ReadOnly)) {
|
||||
qCritical("Unable to open file %s.", qPrintable(fileName));
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
KeePass2Reader reader;
|
||||
Database* db = reader.readDatabase(&dbFile, key);
|
||||
|
||||
if (reader.hasError()) {
|
||||
qCritical("Error while parsing the database: %s", qPrintable(reader.errorString()));
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return db;
|
||||
|
||||
}
|
||||
|
@ -59,6 +59,8 @@ public:
|
||||
QByteArray transformedMasterKey;
|
||||
CompositeKey key;
|
||||
bool hasKey;
|
||||
QByteArray masterSeed;
|
||||
QByteArray challengeResponseKey;
|
||||
};
|
||||
|
||||
Database();
|
||||
@ -89,6 +91,8 @@ public:
|
||||
quint64 transformRounds() const;
|
||||
QByteArray transformedMasterKey() const;
|
||||
const CompositeKey & key() const;
|
||||
QByteArray challengeResponseKey() const;
|
||||
bool challengeMasterSeed(const QByteArray& masterSeed);
|
||||
|
||||
void setCipher(const Uuid& cipher);
|
||||
void setCompressionAlgo(Database::CompressionAlgorithm algo);
|
||||
@ -114,8 +118,9 @@ public:
|
||||
Uuid uuid();
|
||||
|
||||
static Database* databaseByUuid(const Uuid& uuid);
|
||||
static Database* openDatabaseFile(QString fileName, CompositeKey key);
|
||||
|
||||
Q_SIGNALS:
|
||||
signals:
|
||||
void groupDataChanged(Group* group);
|
||||
void groupAboutToAdd(Group* group, int index);
|
||||
void groupAdded();
|
||||
@ -127,7 +132,7 @@ Q_SIGNALS:
|
||||
void modified();
|
||||
void modifiedImmediate();
|
||||
|
||||
private Q_SLOTS:
|
||||
private slots:
|
||||
void startModifiedTimer();
|
||||
|
||||
private:
|
||||
|
@ -62,7 +62,7 @@ template <class T> inline bool Entry::set(T& property, const T& value)
|
||||
{
|
||||
if (property != value) {
|
||||
property = value;
|
||||
Q_EMIT modified();
|
||||
emit modified();
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
@ -299,7 +299,7 @@ void Entry::setIcon(int iconNumber)
|
||||
m_data.iconNumber = iconNumber;
|
||||
m_data.customIcon = Uuid();
|
||||
|
||||
Q_EMIT modified();
|
||||
emit modified();
|
||||
emitDataChanged();
|
||||
}
|
||||
}
|
||||
@ -312,7 +312,7 @@ void Entry::setIcon(const Uuid& uuid)
|
||||
m_data.customIcon = uuid;
|
||||
m_data.iconNumber = 0;
|
||||
|
||||
Q_EMIT modified();
|
||||
emit modified();
|
||||
emitDataChanged();
|
||||
}
|
||||
}
|
||||
@ -392,7 +392,7 @@ void Entry::setExpires(const bool& value)
|
||||
{
|
||||
if (m_data.timeInfo.expires() != value) {
|
||||
m_data.timeInfo.setExpires(value);
|
||||
Q_EMIT modified();
|
||||
emit modified();
|
||||
}
|
||||
}
|
||||
|
||||
@ -400,7 +400,7 @@ void Entry::setExpiryTime(const QDateTime& dateTime)
|
||||
{
|
||||
if (m_data.timeInfo.expiryTime() != dateTime) {
|
||||
m_data.timeInfo.setExpiryTime(dateTime);
|
||||
Q_EMIT modified();
|
||||
emit modified();
|
||||
}
|
||||
}
|
||||
|
||||
@ -419,7 +419,7 @@ void Entry::addHistoryItem(Entry* entry)
|
||||
Q_ASSERT(!entry->parent());
|
||||
|
||||
m_history.append(entry);
|
||||
Q_EMIT modified();
|
||||
emit modified();
|
||||
}
|
||||
|
||||
void Entry::removeHistoryItems(const QList<Entry*>& historyEntries)
|
||||
@ -437,7 +437,7 @@ void Entry::removeHistoryItems(const QList<Entry*>& historyEntries)
|
||||
delete entry;
|
||||
}
|
||||
|
||||
Q_EMIT modified();
|
||||
emit modified();
|
||||
}
|
||||
|
||||
void Entry::truncateHistory()
|
||||
@ -633,7 +633,7 @@ void Entry::setGroup(Group* group)
|
||||
|
||||
void Entry::emitDataChanged()
|
||||
{
|
||||
Q_EMIT dataChanged(this);
|
||||
emit dataChanged(this);
|
||||
}
|
||||
|
||||
const Database* Entry::database() const
|
||||
@ -649,7 +649,8 @@ const Database* Entry::database() const
|
||||
QString Entry::resolveMultiplePlaceholders(const QString& str) const
|
||||
{
|
||||
QString result = str;
|
||||
QRegExp tmplRegEx("({.*})", Qt::CaseInsensitive, QRegExp::RegExp2);
|
||||
QRegExp tmplRegEx("(\\{.*\\})", Qt::CaseInsensitive, QRegExp::RegExp2);
|
||||
tmplRegEx.setMinimal(true);
|
||||
QStringList tmplList;
|
||||
int pos = 0;
|
||||
|
||||
|
@ -147,7 +147,7 @@ public:
|
||||
|
||||
void setUpdateTimeinfo(bool value);
|
||||
|
||||
Q_SIGNALS:
|
||||
signals:
|
||||
/**
|
||||
* Emitted when a default attribute has been changed.
|
||||
*/
|
||||
@ -155,7 +155,7 @@ Q_SIGNALS:
|
||||
|
||||
void modified();
|
||||
|
||||
private Q_SLOTS:
|
||||
private slots:
|
||||
void emitDataChanged();
|
||||
void updateTimeinfo();
|
||||
void updateModifiedSinceBegin();
|
||||
|
@ -48,7 +48,7 @@ void EntryAttachments::set(const QString& key, const QByteArray& value)
|
||||
bool addAttachment = !m_attachments.contains(key);
|
||||
|
||||
if (addAttachment) {
|
||||
Q_EMIT aboutToBeAdded(key);
|
||||
emit aboutToBeAdded(key);
|
||||
}
|
||||
|
||||
if (addAttachment || m_attachments.value(key) != value) {
|
||||
@ -57,14 +57,14 @@ void EntryAttachments::set(const QString& key, const QByteArray& value)
|
||||
}
|
||||
|
||||
if (addAttachment) {
|
||||
Q_EMIT added(key);
|
||||
emit added(key);
|
||||
}
|
||||
else {
|
||||
Q_EMIT keyModified(key);
|
||||
emit keyModified(key);
|
||||
}
|
||||
|
||||
if (emitModified) {
|
||||
Q_EMIT modified();
|
||||
emit modified();
|
||||
}
|
||||
}
|
||||
|
||||
@ -75,12 +75,12 @@ void EntryAttachments::remove(const QString& key)
|
||||
return;
|
||||
}
|
||||
|
||||
Q_EMIT aboutToBeRemoved(key);
|
||||
emit aboutToBeRemoved(key);
|
||||
|
||||
m_attachments.remove(key);
|
||||
|
||||
Q_EMIT removed(key);
|
||||
Q_EMIT modified();
|
||||
emit removed(key);
|
||||
emit modified();
|
||||
}
|
||||
|
||||
void EntryAttachments::clear()
|
||||
@ -89,23 +89,23 @@ void EntryAttachments::clear()
|
||||
return;
|
||||
}
|
||||
|
||||
Q_EMIT aboutToBeReset();
|
||||
emit aboutToBeReset();
|
||||
|
||||
m_attachments.clear();
|
||||
|
||||
Q_EMIT reset();
|
||||
Q_EMIT modified();
|
||||
emit reset();
|
||||
emit modified();
|
||||
}
|
||||
|
||||
void EntryAttachments::copyDataFrom(const EntryAttachments* other)
|
||||
{
|
||||
if (*this != *other) {
|
||||
Q_EMIT aboutToBeReset();
|
||||
emit aboutToBeReset();
|
||||
|
||||
m_attachments = other->m_attachments;
|
||||
|
||||
Q_EMIT reset();
|
||||
Q_EMIT modified();
|
||||
emit reset();
|
||||
emit modified();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -38,7 +38,7 @@ public:
|
||||
bool operator==(const EntryAttachments& other) const;
|
||||
bool operator!=(const EntryAttachments& other) const;
|
||||
|
||||
Q_SIGNALS:
|
||||
signals:
|
||||
void modified();
|
||||
void keyModified(const QString& key);
|
||||
void aboutToBeAdded(const QString& key);
|
||||
|
@ -98,7 +98,7 @@ void EntryAttributes::set(const QString& key, const QString& value, bool protect
|
||||
bool defaultAttribute = isDefaultAttribute(key);
|
||||
|
||||
if (addAttribute && !defaultAttribute) {
|
||||
Q_EMIT aboutToBeAdded(key);
|
||||
emit aboutToBeAdded(key);
|
||||
}
|
||||
|
||||
if (addAttribute || changeValue) {
|
||||
@ -117,17 +117,17 @@ void EntryAttributes::set(const QString& key, const QString& value, bool protect
|
||||
}
|
||||
|
||||
if (emitModified) {
|
||||
Q_EMIT modified();
|
||||
emit modified();
|
||||
}
|
||||
|
||||
if (defaultAttribute && changeValue) {
|
||||
Q_EMIT defaultKeyModified();
|
||||
emit defaultKeyModified();
|
||||
}
|
||||
else if (addAttribute) {
|
||||
Q_EMIT added(key);
|
||||
emit added(key);
|
||||
}
|
||||
else if (emitModified) {
|
||||
Q_EMIT customKeyModified(key);
|
||||
emit customKeyModified(key);
|
||||
}
|
||||
}
|
||||
|
||||
@ -140,13 +140,13 @@ void EntryAttributes::remove(const QString& key)
|
||||
return;
|
||||
}
|
||||
|
||||
Q_EMIT aboutToBeRemoved(key);
|
||||
emit aboutToBeRemoved(key);
|
||||
|
||||
m_attributes.remove(key);
|
||||
m_protectedAttributes.remove(key);
|
||||
|
||||
Q_EMIT removed(key);
|
||||
Q_EMIT modified();
|
||||
emit removed(key);
|
||||
emit modified();
|
||||
}
|
||||
|
||||
void EntryAttributes::rename(const QString& oldKey, const QString& newKey)
|
||||
@ -167,7 +167,7 @@ void EntryAttributes::rename(const QString& oldKey, const QString& newKey)
|
||||
QString data = value(oldKey);
|
||||
bool protect = isProtected(oldKey);
|
||||
|
||||
Q_EMIT aboutToRename(oldKey, newKey);
|
||||
emit aboutToRename(oldKey, newKey);
|
||||
|
||||
m_attributes.remove(oldKey);
|
||||
m_attributes.insert(newKey, data);
|
||||
@ -176,8 +176,8 @@ void EntryAttributes::rename(const QString& oldKey, const QString& newKey)
|
||||
m_protectedAttributes.insert(newKey);
|
||||
}
|
||||
|
||||
Q_EMIT modified();
|
||||
Q_EMIT renamed(oldKey, newKey);
|
||||
emit modified();
|
||||
emit renamed(oldKey, newKey);
|
||||
}
|
||||
|
||||
void EntryAttributes::copyCustomKeysFrom(const EntryAttributes* other)
|
||||
@ -186,7 +186,7 @@ void EntryAttributes::copyCustomKeysFrom(const EntryAttributes* other)
|
||||
return;
|
||||
}
|
||||
|
||||
Q_EMIT aboutToBeReset();
|
||||
emit aboutToBeReset();
|
||||
|
||||
// remove all non-default keys
|
||||
const QList<QString> keyList = keys();
|
||||
@ -207,8 +207,8 @@ void EntryAttributes::copyCustomKeysFrom(const EntryAttributes* other)
|
||||
}
|
||||
}
|
||||
|
||||
Q_EMIT reset();
|
||||
Q_EMIT modified();
|
||||
emit reset();
|
||||
emit modified();
|
||||
}
|
||||
|
||||
bool EntryAttributes::areCustomKeysDifferent(const EntryAttributes* other)
|
||||
@ -235,13 +235,13 @@ bool EntryAttributes::areCustomKeysDifferent(const EntryAttributes* other)
|
||||
void EntryAttributes::copyDataFrom(const EntryAttributes* other)
|
||||
{
|
||||
if (*this != *other) {
|
||||
Q_EMIT aboutToBeReset();
|
||||
emit aboutToBeReset();
|
||||
|
||||
m_attributes = other->m_attributes;
|
||||
m_protectedAttributes = other->m_protectedAttributes;
|
||||
|
||||
Q_EMIT reset();
|
||||
Q_EMIT modified();
|
||||
emit reset();
|
||||
emit modified();
|
||||
}
|
||||
}
|
||||
|
||||
@ -259,7 +259,7 @@ bool EntryAttributes::operator!=(const EntryAttributes& other) const
|
||||
|
||||
void EntryAttributes::clear()
|
||||
{
|
||||
Q_EMIT aboutToBeReset();
|
||||
emit aboutToBeReset();
|
||||
|
||||
m_attributes.clear();
|
||||
m_protectedAttributes.clear();
|
||||
@ -268,8 +268,8 @@ void EntryAttributes::clear()
|
||||
m_attributes.insert(key, "");
|
||||
}
|
||||
|
||||
Q_EMIT reset();
|
||||
Q_EMIT modified();
|
||||
emit reset();
|
||||
emit modified();
|
||||
}
|
||||
|
||||
int EntryAttributes::attributesSize()
|
||||
|
@ -57,7 +57,7 @@ public:
|
||||
static const QString RememberCmdExecAttr;
|
||||
static bool isDefaultAttribute(const QString& key);
|
||||
|
||||
Q_SIGNALS:
|
||||
signals:
|
||||
void modified();
|
||||
void defaultKeyModified();
|
||||
void customKeyModified(const QString& key);
|
||||
|
@ -74,7 +74,7 @@ template <class P, class V> inline bool Group::set(P& property, const V& value)
|
||||
if (property != value) {
|
||||
property = value;
|
||||
updateTimeinfo();
|
||||
Q_EMIT modified();
|
||||
emit modified();
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
@ -249,7 +249,7 @@ void Group::setUuid(const Uuid& uuid)
|
||||
void Group::setName(const QString& name)
|
||||
{
|
||||
if (set(m_data.name, name)) {
|
||||
Q_EMIT dataChanged(this);
|
||||
emit dataChanged(this);
|
||||
}
|
||||
}
|
||||
|
||||
@ -267,8 +267,8 @@ void Group::setIcon(int iconNumber)
|
||||
m_data.customIcon = Uuid();
|
||||
|
||||
updateTimeinfo();
|
||||
Q_EMIT modified();
|
||||
Q_EMIT dataChanged(this);
|
||||
emit modified();
|
||||
emit dataChanged(this);
|
||||
}
|
||||
}
|
||||
|
||||
@ -281,8 +281,8 @@ void Group::setIcon(const Uuid& uuid)
|
||||
m_data.iconNumber = 0;
|
||||
|
||||
updateTimeinfo();
|
||||
Q_EMIT modified();
|
||||
Q_EMIT dataChanged(this);
|
||||
emit modified();
|
||||
emit dataChanged(this);
|
||||
}
|
||||
}
|
||||
|
||||
@ -296,7 +296,7 @@ void Group::setExpanded(bool expanded)
|
||||
if (m_data.isExpanded != expanded) {
|
||||
m_data.isExpanded = expanded;
|
||||
updateTimeinfo();
|
||||
Q_EMIT modified();
|
||||
emit modified();
|
||||
}
|
||||
}
|
||||
|
||||
@ -325,7 +325,7 @@ void Group::setExpires(bool value)
|
||||
if (m_data.timeInfo.expires() != value) {
|
||||
m_data.timeInfo.setExpires(value);
|
||||
updateTimeinfo();
|
||||
Q_EMIT modified();
|
||||
emit modified();
|
||||
}
|
||||
}
|
||||
|
||||
@ -334,7 +334,7 @@ void Group::setExpiryTime(const QDateTime& dateTime)
|
||||
if (m_data.timeInfo.expiryTime() != dateTime) {
|
||||
m_data.timeInfo.setExpiryTime(dateTime);
|
||||
updateTimeinfo();
|
||||
Q_EMIT modified();
|
||||
emit modified();
|
||||
}
|
||||
}
|
||||
|
||||
@ -391,12 +391,12 @@ void Group::setParent(Group* parent, int index)
|
||||
recSetDatabase(parent->m_db);
|
||||
}
|
||||
QObject::setParent(parent);
|
||||
Q_EMIT aboutToAdd(this, index);
|
||||
emit aboutToAdd(this, index);
|
||||
Q_ASSERT(index <= parent->m_children.size());
|
||||
parent->m_children.insert(index, this);
|
||||
}
|
||||
else {
|
||||
Q_EMIT aboutToMove(this, parent, index);
|
||||
emit aboutToMove(this, parent, index);
|
||||
m_parent->m_children.removeAll(this);
|
||||
m_parent = parent;
|
||||
QObject::setParent(parent);
|
||||
@ -408,13 +408,13 @@ void Group::setParent(Group* parent, int index)
|
||||
m_data.timeInfo.setLocationChanged(QDateTime::currentDateTimeUtc());
|
||||
}
|
||||
|
||||
Q_EMIT modified();
|
||||
emit modified();
|
||||
|
||||
if (!moveWithinDatabase) {
|
||||
Q_EMIT added();
|
||||
emit added();
|
||||
}
|
||||
else {
|
||||
Q_EMIT moved();
|
||||
emit moved();
|
||||
}
|
||||
}
|
||||
|
||||
@ -566,7 +566,7 @@ void Group::merge(const Group* other)
|
||||
}
|
||||
}
|
||||
|
||||
Q_EMIT modified();
|
||||
emit modified();
|
||||
}
|
||||
|
||||
Group* Group::findChildByName(const QString& name)
|
||||
@ -623,7 +623,7 @@ void Group::addEntry(Entry* entry)
|
||||
Q_ASSERT(entry);
|
||||
Q_ASSERT(!m_entries.contains(entry));
|
||||
|
||||
Q_EMIT entryAboutToAdd(entry);
|
||||
emit entryAboutToAdd(entry);
|
||||
|
||||
m_entries << entry;
|
||||
connect(entry, SIGNAL(dataChanged(Entry*)), SIGNAL(entryDataChanged(Entry*)));
|
||||
@ -631,23 +631,23 @@ void Group::addEntry(Entry* entry)
|
||||
connect(entry, SIGNAL(modified()), m_db, SIGNAL(modifiedImmediate()));
|
||||
}
|
||||
|
||||
Q_EMIT modified();
|
||||
Q_EMIT entryAdded(entry);
|
||||
emit modified();
|
||||
emit entryAdded(entry);
|
||||
}
|
||||
|
||||
void Group::removeEntry(Entry* entry)
|
||||
{
|
||||
Q_ASSERT(m_entries.contains(entry));
|
||||
|
||||
Q_EMIT entryAboutToRemove(entry);
|
||||
emit entryAboutToRemove(entry);
|
||||
|
||||
entry->disconnect(this);
|
||||
if (m_db) {
|
||||
entry->disconnect(m_db);
|
||||
}
|
||||
m_entries.removeAll(entry);
|
||||
Q_EMIT modified();
|
||||
Q_EMIT entryRemoved(entry);
|
||||
emit modified();
|
||||
emit entryRemoved(entry);
|
||||
}
|
||||
|
||||
void Group::recSetDatabase(Database* db)
|
||||
@ -693,10 +693,10 @@ void Group::recSetDatabase(Database* db)
|
||||
void Group::cleanupParent()
|
||||
{
|
||||
if (m_parent) {
|
||||
Q_EMIT aboutToRemove(this);
|
||||
emit aboutToRemove(this);
|
||||
m_parent->m_children.removeAll(this);
|
||||
Q_EMIT modified();
|
||||
Q_EMIT removed();
|
||||
emit modified();
|
||||
emit removed();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -122,7 +122,7 @@ public:
|
||||
void copyDataFrom(const Group* other);
|
||||
void merge(const Group* other);
|
||||
|
||||
Q_SIGNALS:
|
||||
signals:
|
||||
void dataChanged(Group* group);
|
||||
|
||||
void aboutToAdd(Group* group, int index);
|
||||
|
@ -73,7 +73,7 @@ void InactivityTimer::timeout()
|
||||
}
|
||||
|
||||
if (m_active && !m_timer->isActive()) {
|
||||
Q_EMIT inactivityDetected();
|
||||
emit inactivityDetected();
|
||||
}
|
||||
|
||||
m_emitMutx.unlock();
|
||||
|
@ -33,13 +33,13 @@ public:
|
||||
void activate();
|
||||
void deactivate();
|
||||
|
||||
Q_SIGNALS:
|
||||
signals:
|
||||
void inactivityDetected();
|
||||
|
||||
protected:
|
||||
bool eventFilter(QObject* watched, QEvent* event);
|
||||
|
||||
private Q_SLOTS:
|
||||
private slots:
|
||||
void timeout();
|
||||
|
||||
private:
|
||||
|
@ -55,7 +55,7 @@ template <class P, class V> bool Metadata::set(P& property, const V& value)
|
||||
{
|
||||
if (property != value) {
|
||||
property = value;
|
||||
Q_EMIT modified();
|
||||
emit modified();
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
@ -69,7 +69,7 @@ template <class P, class V> bool Metadata::set(P& property, const V& value, QDat
|
||||
if (m_updateDatetime) {
|
||||
dateTime = QDateTime::currentDateTimeUtc();
|
||||
}
|
||||
Q_EMIT modified();
|
||||
emit modified();
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
@ -308,7 +308,7 @@ void Metadata::setGenerator(const QString& value)
|
||||
void Metadata::setName(const QString& value)
|
||||
{
|
||||
if (set(m_data.name, value, m_data.nameChanged)) {
|
||||
Q_EMIT nameTextChanged();
|
||||
emit nameTextChanged();
|
||||
}
|
||||
}
|
||||
|
||||
@ -391,7 +391,7 @@ void Metadata::addCustomIcon(const Uuid& uuid, const QImage& icon)
|
||||
m_customIconScaledCacheKeys[uuid] = QPixmapCache::Key();
|
||||
m_customIconsOrder.append(uuid);
|
||||
Q_ASSERT(m_customIcons.count() == m_customIconsOrder.count());
|
||||
Q_EMIT modified();
|
||||
emit modified();
|
||||
}
|
||||
|
||||
void Metadata::addCustomIconScaled(const Uuid& uuid, const QImage& icon)
|
||||
@ -422,7 +422,7 @@ void Metadata::removeCustomIcon(const Uuid& uuid)
|
||||
m_customIconScaledCacheKeys.remove(uuid);
|
||||
m_customIconsOrder.removeAll(uuid);
|
||||
Q_ASSERT(m_customIcons.count() == m_customIconsOrder.count());
|
||||
Q_EMIT modified();
|
||||
emit modified();
|
||||
}
|
||||
|
||||
void Metadata::copyCustomIcons(const QSet<Uuid>& iconList, const Metadata* otherMetadata)
|
||||
@ -504,7 +504,7 @@ void Metadata::addCustomField(const QString& key, const QString& value)
|
||||
Q_ASSERT(!m_customFields.contains(key));
|
||||
|
||||
m_customFields.insert(key, value);
|
||||
Q_EMIT modified();
|
||||
emit modified();
|
||||
}
|
||||
|
||||
void Metadata::removeCustomField(const QString& key)
|
||||
@ -512,5 +512,5 @@ void Metadata::removeCustomField(const QString& key)
|
||||
Q_ASSERT(m_customFields.contains(key));
|
||||
|
||||
m_customFields.remove(key);
|
||||
Q_EMIT modified();
|
||||
emit modified();
|
||||
}
|
||||
|
@ -146,7 +146,7 @@ public:
|
||||
*/
|
||||
void copyAttributesFrom(const Metadata* other);
|
||||
|
||||
Q_SIGNALS:
|
||||
signals:
|
||||
void nameTextChanged();
|
||||
void modified();
|
||||
|
||||
|
@ -97,11 +97,11 @@ QString PasswordGenerator::generatePassword() const
|
||||
|
||||
int PasswordGenerator::getbits() const
|
||||
{
|
||||
QVector<PasswordGroup> groups = passwordGroups();
|
||||
const QVector<PasswordGroup> groups = passwordGroups();
|
||||
|
||||
int bits = 0;
|
||||
QVector<QChar> passwordChars;
|
||||
Q_FOREACH (const PasswordGroup& group, groups) {
|
||||
for (const PasswordGroup& group: groups) {
|
||||
bits += group.size();
|
||||
}
|
||||
|
||||
|
@ -113,8 +113,14 @@ Database* KeePass2Reader::readDatabase(QIODevice* device, const CompositeKey& ke
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (m_db->challengeMasterSeed(m_masterSeed) == false) {
|
||||
raiseError(tr("Unable to issue challenge-response."));
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
CryptoHash hash(CryptoHash::Sha256);
|
||||
hash.addData(m_masterSeed);
|
||||
hash.addData(m_db->challengeResponseKey());
|
||||
hash.addData(m_db->transformedMasterKey());
|
||||
QByteArray finalKey = hash.result();
|
||||
|
||||
|
@ -51,8 +51,14 @@ void KeePass2Writer::writeDatabase(QIODevice* device, Database* db)
|
||||
QByteArray startBytes = randomGen()->randomArray(32);
|
||||
QByteArray endOfHeader = "\r\n\r\n";
|
||||
|
||||
if (db->challengeMasterSeed(masterSeed) == false) {
|
||||
raiseError("Unable to issue challenge-response.");
|
||||
return;
|
||||
}
|
||||
|
||||
CryptoHash hash(CryptoHash::Sha256);
|
||||
hash.addData(masterSeed);
|
||||
hash.addData(db->challengeResponseKey());
|
||||
Q_ASSERT(!db->transformedMasterKey().isEmpty());
|
||||
hash.addData(db->transformedMasterKey());
|
||||
QByteArray finalKey = hash.result();
|
||||
|
@ -87,6 +87,11 @@ Application::Application(int& argc, char** argv)
|
||||
#endif
|
||||
}
|
||||
|
||||
QWidget* Application::mainWindow() const
|
||||
{
|
||||
return m_mainWindow;
|
||||
}
|
||||
|
||||
void Application::setMainWindow(QWidget* mainWindow)
|
||||
{
|
||||
m_mainWindow = mainWindow;
|
||||
@ -96,7 +101,7 @@ bool Application::event(QEvent* event)
|
||||
{
|
||||
// Handle Apple QFileOpenEvent from finder (double click on .kdbx file)
|
||||
if (event->type() == QEvent::FileOpen) {
|
||||
Q_EMIT openFile(static_cast<QFileOpenEvent*>(event)->file());
|
||||
emit openFile(static_cast<QFileOpenEvent*>(event)->file());
|
||||
return true;
|
||||
}
|
||||
#ifdef Q_OS_MAC
|
||||
@ -148,7 +153,7 @@ void Application::handleUnixSignal(int sig)
|
||||
case SIGTERM:
|
||||
{
|
||||
char buf = 0;
|
||||
::write(unixSignalSocket[0], &buf, sizeof(buf));
|
||||
Q_UNUSED(::write(unixSignalSocket[0], &buf, sizeof(buf)));
|
||||
return;
|
||||
}
|
||||
case SIGHUP:
|
||||
@ -160,7 +165,7 @@ void Application::quitBySignal()
|
||||
{
|
||||
m_unixSignalNotifier->setEnabled(false);
|
||||
char buf;
|
||||
::read(unixSignalSocket[1], &buf, sizeof(buf));
|
||||
Q_UNUSED(::read(unixSignalSocket[1], &buf, sizeof(buf)));
|
||||
|
||||
if (nullptr != m_mainWindow)
|
||||
static_cast<MainWindow*>(m_mainWindow)->appExit();
|
||||
|
@ -29,14 +29,15 @@ class Application : public QApplication
|
||||
|
||||
public:
|
||||
Application(int& argc, char** argv);
|
||||
QWidget* mainWindow() const;
|
||||
void setMainWindow(QWidget* mainWindow);
|
||||
|
||||
bool event(QEvent* event) override;
|
||||
|
||||
Q_SIGNALS:
|
||||
signals:
|
||||
void openFile(const QString& filename);
|
||||
|
||||
private Q_SLOTS:
|
||||
private slots:
|
||||
#if defined(Q_OS_UNIX)
|
||||
void quitBySignal();
|
||||
#endif
|
||||
|
@ -21,8 +21,16 @@
|
||||
#include "core/FilePath.h"
|
||||
#include "keys/FileKey.h"
|
||||
#include "keys/PasswordKey.h"
|
||||
#include "keys/YkChallengeResponseKey.h"
|
||||
#include "gui/FileDialog.h"
|
||||
#include "gui/MessageBox.h"
|
||||
#include "crypto/Random.h"
|
||||
#include "MainWindow.h"
|
||||
|
||||
#include "config-keepassx.h"
|
||||
|
||||
#include <QtConcurrentRun>
|
||||
#include <QSharedPointer>
|
||||
|
||||
ChangeMasterKeyWidget::ChangeMasterKeyWidget(QWidget* parent)
|
||||
: DialogyWidget(parent)
|
||||
@ -32,13 +40,35 @@ ChangeMasterKeyWidget::ChangeMasterKeyWidget(QWidget* parent)
|
||||
|
||||
m_ui->messageWidget->setHidden(true);
|
||||
|
||||
connect(m_ui->buttonBox, SIGNAL(accepted()), SLOT(generateKey()));
|
||||
connect(m_ui->buttonBox, SIGNAL(rejected()), SLOT(reject()));
|
||||
m_ui->togglePasswordButton->setIcon(filePath()->onOffIcon("actions", "password-show"));
|
||||
connect(m_ui->togglePasswordButton, SIGNAL(toggled(bool)), m_ui->enterPasswordEdit, SLOT(setShowPassword(bool)));
|
||||
m_ui->repeatPasswordEdit->enableVerifyMode(m_ui->enterPasswordEdit);
|
||||
|
||||
connect(m_ui->passwordGroup, SIGNAL(clicked(bool)), SLOT(setOkEnabled()));
|
||||
connect(m_ui->togglePasswordButton, SIGNAL(toggled(bool)), m_ui->enterPasswordEdit, SLOT(setShowPassword(bool)));
|
||||
|
||||
connect(m_ui->keyFileGroup, SIGNAL(clicked(bool)), SLOT(setOkEnabled()));
|
||||
connect(m_ui->createKeyFileButton, SIGNAL(clicked()), SLOT(createKeyFile()));
|
||||
connect(m_ui->browseKeyFileButton, SIGNAL(clicked()), SLOT(browseKeyFile()));
|
||||
connect(m_ui->keyFileCombo, SIGNAL(editTextChanged(QString)), SLOT(setOkEnabled()));
|
||||
|
||||
connect(m_ui->buttonBox, SIGNAL(accepted()), SLOT(generateKey()));
|
||||
connect(m_ui->buttonBox, SIGNAL(rejected()), SLOT(reject()));
|
||||
|
||||
#ifdef WITH_XC_YUBIKEY
|
||||
m_ui->yubikeyProgress->setVisible(false);
|
||||
QSizePolicy sp = m_ui->yubikeyProgress->sizePolicy();
|
||||
sp.setRetainSizeWhenHidden(true);
|
||||
m_ui->yubikeyProgress->setSizePolicy(sp);
|
||||
|
||||
connect(m_ui->challengeResponseGroup, SIGNAL(clicked(bool)), SLOT(challengeResponseGroupToggled(bool)));
|
||||
connect(m_ui->challengeResponseGroup, SIGNAL(clicked(bool)), SLOT(setOkEnabled()));
|
||||
connect(m_ui->buttonRedetectYubikey, SIGNAL(clicked()), SLOT(pollYubikey()));
|
||||
|
||||
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->challengeResponseGroup->setVisible(false);
|
||||
#endif
|
||||
}
|
||||
|
||||
ChangeMasterKeyWidget::~ChangeMasterKeyWidget()
|
||||
@ -81,7 +111,11 @@ void ChangeMasterKeyWidget::clearForms()
|
||||
m_ui->repeatPasswordEdit->setText("");
|
||||
m_ui->keyFileGroup->setChecked(false);
|
||||
m_ui->togglePasswordButton->setChecked(false);
|
||||
// TODO: clear m_ui->keyFileCombo
|
||||
|
||||
#ifdef WITH_XC_YUBIKEY
|
||||
m_ui->challengeResponseGroup->setChecked(false);
|
||||
m_ui->comboChallengeResponse->clear();
|
||||
#endif
|
||||
|
||||
m_ui->enterPasswordEdit->setFocus();
|
||||
}
|
||||
@ -103,9 +137,9 @@ void ChangeMasterKeyWidget::generateKey()
|
||||
if (m_ui->passwordGroup->isChecked()) {
|
||||
if (m_ui->enterPasswordEdit->text() == m_ui->repeatPasswordEdit->text()) {
|
||||
if (m_ui->enterPasswordEdit->text().isEmpty()) {
|
||||
if (MessageBox::question(this, tr("Question"),
|
||||
tr("Do you really want to use an empty string as password?"),
|
||||
QMessageBox::Yes | QMessageBox::No) != QMessageBox::Yes) {
|
||||
if (MessageBox::warning(this, tr("Empty password"),
|
||||
tr("Do you really want to use an empty string as password?"),
|
||||
QMessageBox::Yes | QMessageBox::No) != QMessageBox::Yes) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -130,14 +164,78 @@ void ChangeMasterKeyWidget::generateKey()
|
||||
m_key.addKey(fileKey);
|
||||
}
|
||||
|
||||
#ifdef WITH_XC_YUBIKEY
|
||||
if (m_ui->challengeResponseGroup->isChecked()) {
|
||||
int selectionIndex = m_ui->comboChallengeResponse->currentIndex();
|
||||
int comboPayload = m_ui->comboChallengeResponse->itemData(selectionIndex).toInt();
|
||||
|
||||
if (0 == comboPayload) {
|
||||
m_ui->messageWidget->showMessage(tr("Changing master key failed: no YubiKey inserted."),
|
||||
MessageWidget::Error);
|
||||
return;
|
||||
}
|
||||
|
||||
// read blocking mode from LSB and slot index number from second LSB
|
||||
bool blocking = comboPayload & 1;
|
||||
int slot = comboPayload >> 1;
|
||||
auto key = QSharedPointer<YkChallengeResponseKey>(new YkChallengeResponseKey(slot, blocking));
|
||||
m_key.addChallengeResponseKey(key);
|
||||
}
|
||||
#endif
|
||||
|
||||
m_ui->messageWidget->hideMessage();
|
||||
Q_EMIT editFinished(true);
|
||||
emit editFinished(true);
|
||||
}
|
||||
|
||||
|
||||
void ChangeMasterKeyWidget::reject()
|
||||
{
|
||||
Q_EMIT editFinished(false);
|
||||
emit editFinished(false);
|
||||
}
|
||||
|
||||
void ChangeMasterKeyWidget::challengeResponseGroupToggled(bool checked)
|
||||
{
|
||||
if (checked)
|
||||
pollYubikey();
|
||||
}
|
||||
|
||||
void ChangeMasterKeyWidget::pollYubikey()
|
||||
{
|
||||
m_ui->buttonRedetectYubikey->setEnabled(false);
|
||||
m_ui->comboChallengeResponse->setEnabled(false);
|
||||
m_ui->comboChallengeResponse->clear();
|
||||
m_ui->yubikeyProgress->setVisible(true);
|
||||
setOkEnabled();
|
||||
|
||||
// YubiKey init is slow, detect asynchronously to not block the UI
|
||||
QtConcurrent::run(YubiKey::instance(), &YubiKey::detect);
|
||||
}
|
||||
|
||||
void ChangeMasterKeyWidget::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(m_ui->challengeResponseGroup->isChecked());
|
||||
m_ui->buttonRedetectYubikey->setEnabled(m_ui->challengeResponseGroup->isChecked());
|
||||
m_ui->yubikeyProgress->setVisible(false);
|
||||
setOkEnabled();
|
||||
}
|
||||
|
||||
void ChangeMasterKeyWidget::noYubikeyFound()
|
||||
{
|
||||
m_ui->buttonRedetectYubikey->setEnabled(m_ui->challengeResponseGroup->isChecked());
|
||||
m_ui->yubikeyProgress->setVisible(false);
|
||||
setOkEnabled();
|
||||
}
|
||||
|
||||
void ChangeMasterKeyWidget::setOkEnabled()
|
||||
{
|
||||
bool ok = m_ui->passwordGroup->isChecked() ||
|
||||
(m_ui->challengeResponseGroup->isChecked() && !m_ui->comboChallengeResponse->currentText().isEmpty()) ||
|
||||
(m_ui->keyFileGroup->isChecked() && !m_ui->keyFileCombo->currentText().isEmpty());
|
||||
|
||||
m_ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(ok);
|
||||
}
|
||||
|
||||
void ChangeMasterKeyWidget::setCancelEnabled(bool enabled)
|
||||
|
@ -38,16 +38,23 @@ public:
|
||||
void clearForms();
|
||||
CompositeKey newMasterKey();
|
||||
QLabel* headlineLabel();
|
||||
|
||||
public slots:
|
||||
void setOkEnabled();
|
||||
void setCancelEnabled(bool enabled);
|
||||
|
||||
Q_SIGNALS:
|
||||
signals:
|
||||
void editFinished(bool accepted);
|
||||
|
||||
private Q_SLOTS:
|
||||
private slots:
|
||||
void generateKey();
|
||||
void reject();
|
||||
void createKeyFile();
|
||||
void browseKeyFile();
|
||||
void yubikeyDetected(int slot, bool blocking);
|
||||
void noYubikeyFound();
|
||||
void challengeResponseGroupToggled(bool checked);
|
||||
void pollYubikey();
|
||||
|
||||
private:
|
||||
const QScopedPointer<Ui::ChangeMasterKeyWidget> m_ui;
|
||||
|
@ -7,7 +7,7 @@
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>818</width>
|
||||
<height>397</height>
|
||||
<height>471</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
@ -90,7 +90,7 @@
|
||||
<item>
|
||||
<widget class="QGroupBox" name="keyFileGroup">
|
||||
<property name="title">
|
||||
<string>Key file</string>
|
||||
<string>&Key file</string>
|
||||
</property>
|
||||
<property name="checkable">
|
||||
<bool>true</bool>
|
||||
@ -126,6 +126,67 @@
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="challengeResponseGroup">
|
||||
<property name="enabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="title">
|
||||
<string>Cha&llenge Response</string>
|
||||
</property>
|
||||
<property name="checkable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="checked">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_3">
|
||||
<item row="0" column="0">
|
||||
<layout class="QGridLayout" name="gridLayout_4">
|
||||
<property name="verticalSpacing">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item row="0" column="1">
|
||||
<widget class="QPushButton" name="buttonRedetectYubikey">
|
||||
<property name="text">
|
||||
<string>Refresh</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QComboBox" name="comboChallengeResponse">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QProgressBar" name="yubikeyProgress">
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>16777215</width>
|
||||
<height>2</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>-1</number>
|
||||
</property>
|
||||
<property name="textVisible">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer">
|
||||
<property name="orientation">
|
||||
|
@ -31,10 +31,10 @@ public:
|
||||
|
||||
static Clipboard* instance();
|
||||
|
||||
public Q_SLOTS:
|
||||
public slots:
|
||||
void clearCopiedText();
|
||||
|
||||
private Q_SLOTS:
|
||||
private slots:
|
||||
void clearClipboard();
|
||||
|
||||
private:
|
||||
|
@ -39,7 +39,7 @@ public:
|
||||
private:
|
||||
QScopedPointer<Ui::CloneDialog> m_ui;
|
||||
|
||||
private Q_SLOTS:
|
||||
private slots:
|
||||
void cloneEntry();
|
||||
|
||||
protected:
|
||||
|
@ -27,6 +27,14 @@
|
||||
#include "format/KeePass2Reader.h"
|
||||
#include "keys/FileKey.h"
|
||||
#include "keys/PasswordKey.h"
|
||||
#include "crypto/Random.h"
|
||||
#include "keys/YkChallengeResponseKey.h"
|
||||
|
||||
#include "config-keepassx.h"
|
||||
|
||||
#include <QtConcurrentRun>
|
||||
#include <QSharedPointer>
|
||||
|
||||
|
||||
DatabaseOpenWidget::DatabaseOpenWidget(QWidget* parent)
|
||||
: DialogyWidget(parent)
|
||||
@ -42,8 +50,6 @@ DatabaseOpenWidget::DatabaseOpenWidget(QWidget* parent)
|
||||
font.setPointSize(font.pointSize() + 2);
|
||||
m_ui->labelHeadline->setFont(font);
|
||||
|
||||
m_ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(false);
|
||||
|
||||
m_ui->buttonTogglePassword->setIcon(filePath()->onOffIcon("actions", "password-show"));
|
||||
connect(m_ui->buttonTogglePassword, SIGNAL(toggled(bool)),
|
||||
m_ui->editPassword, SLOT(setShowPassword(bool)));
|
||||
@ -54,7 +60,25 @@ DatabaseOpenWidget::DatabaseOpenWidget(QWidget* parent)
|
||||
|
||||
connect(m_ui->buttonBox, SIGNAL(accepted()), SLOT(openDatabase()));
|
||||
connect(m_ui->buttonBox, SIGNAL(rejected()), SLOT(reject()));
|
||||
|
||||
|
||||
#ifdef WITH_XC_YUBIKEY
|
||||
m_ui->yubikeyProgress->setVisible(false);
|
||||
QSizePolicy sp = m_ui->yubikeyProgress->sizePolicy();
|
||||
sp.setRetainSizeWhenHidden(true);
|
||||
m_ui->yubikeyProgress->setSizePolicy(sp);
|
||||
|
||||
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);
|
||||
m_ui->comboChallengeResponse->setVisible(false);
|
||||
m_ui->yubikeyProgress->setVisible(false);
|
||||
#endif
|
||||
|
||||
#ifdef Q_OS_MACOS
|
||||
// add random padding to layouts to align widgets properly
|
||||
m_ui->dialogButtonsLayout->setContentsMargins(10, 0, 15, 0);
|
||||
@ -71,6 +95,10 @@ void DatabaseOpenWidget::showEvent(QShowEvent* event)
|
||||
{
|
||||
DialogyWidget::showEvent(event);
|
||||
m_ui->editPassword->setFocus();
|
||||
|
||||
#ifdef WITH_XC_YUBIKEY
|
||||
pollYubikey();
|
||||
#endif
|
||||
}
|
||||
|
||||
void DatabaseOpenWidget::load(const QString& filename)
|
||||
@ -87,7 +115,6 @@ void DatabaseOpenWidget::load(const QString& filename)
|
||||
}
|
||||
}
|
||||
|
||||
m_ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(true);
|
||||
m_ui->editPassword->setFocus();
|
||||
}
|
||||
|
||||
@ -130,7 +157,7 @@ void DatabaseOpenWidget::openDatabase()
|
||||
if (m_ui->messageWidget->isVisible()) {
|
||||
m_ui->messageWidget->animatedHide();
|
||||
}
|
||||
Q_EMIT editFinished(true);
|
||||
emit editFinished(true);
|
||||
}
|
||||
else {
|
||||
m_ui->messageWidget->showMessage(tr("Unable to open the database.")
|
||||
@ -148,6 +175,7 @@ CompositeKey DatabaseOpenWidget::databaseKey()
|
||||
}
|
||||
|
||||
QHash<QString, QVariant> lastKeyFiles = config()->get("LastKeyFiles").toHash();
|
||||
QHash<QString, QVariant> lastChallengeResponse = config()->get("LastChallengeResponse").toHash();
|
||||
|
||||
if (m_ui->checkKeyFile->isChecked()) {
|
||||
FileKey key;
|
||||
@ -160,21 +188,43 @@ CompositeKey DatabaseOpenWidget::databaseKey()
|
||||
}
|
||||
masterKey.addKey(key);
|
||||
lastKeyFiles[m_filename] = keyFilename;
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
lastKeyFiles.remove(m_filename);
|
||||
}
|
||||
|
||||
if (m_ui->checkChallengeResponse->isChecked()) {
|
||||
lastChallengeResponse[m_filename] = true;
|
||||
} else {
|
||||
lastChallengeResponse.remove(m_filename);
|
||||
}
|
||||
|
||||
if (config()->get("RememberLastKeyFiles").toBool()) {
|
||||
config()->set("LastKeyFiles", lastKeyFiles);
|
||||
}
|
||||
|
||||
#ifdef WITH_XC_YUBIKEY
|
||||
if (config()->get("RememberLastKeyFiles").toBool()) {
|
||||
config()->set("LastChallengeResponse", lastChallengeResponse);
|
||||
}
|
||||
|
||||
if (m_ui->checkChallengeResponse->isChecked()) {
|
||||
int selectionIndex = m_ui->comboChallengeResponse->currentIndex();
|
||||
int comboPayload = m_ui->comboChallengeResponse->itemData(selectionIndex).toInt();
|
||||
|
||||
// read blocking mode from LSB and slot index number from second LSB
|
||||
bool blocking = comboPayload & 1;
|
||||
int slot = comboPayload >> 1;
|
||||
auto key = QSharedPointer<YkChallengeResponseKey>(new YkChallengeResponseKey(slot, blocking));
|
||||
masterKey.addChallengeResponseKey(key);
|
||||
}
|
||||
#endif
|
||||
|
||||
return masterKey;
|
||||
}
|
||||
|
||||
void DatabaseOpenWidget::reject()
|
||||
{
|
||||
Q_EMIT editFinished(false);
|
||||
emit editFinished(false);
|
||||
}
|
||||
|
||||
void DatabaseOpenWidget::activatePassword()
|
||||
@ -187,6 +237,11 @@ void DatabaseOpenWidget::activateKeyFile()
|
||||
m_ui->checkKeyFile->setChecked(true);
|
||||
}
|
||||
|
||||
void DatabaseOpenWidget::activateChallengeResponse()
|
||||
{
|
||||
m_ui->checkChallengeResponse->setChecked(true);
|
||||
}
|
||||
|
||||
void DatabaseOpenWidget::browseKeyFile()
|
||||
{
|
||||
QString filters = QString("%1 (*);;%2 (*.key)").arg(tr("All files"), tr("Key files"));
|
||||
@ -196,3 +251,40 @@ void DatabaseOpenWidget::browseKeyFile()
|
||||
m_ui->comboKeyFile->lineEdit()->setText(filename);
|
||||
}
|
||||
}
|
||||
|
||||
void DatabaseOpenWidget::pollYubikey()
|
||||
{
|
||||
m_ui->buttonRedetectYubikey->setEnabled(false);
|
||||
m_ui->checkChallengeResponse->setEnabled(false);
|
||||
m_ui->checkChallengeResponse->setChecked(false);
|
||||
m_ui->comboChallengeResponse->setEnabled(false);
|
||||
m_ui->comboChallengeResponse->clear();
|
||||
m_ui->yubikeyProgress->setVisible(true);
|
||||
|
||||
// YubiKey init is slow, detect asynchronously to not block the UI
|
||||
QtConcurrent::run(YubiKey::instance(), &YubiKey::detect);
|
||||
}
|
||||
|
||||
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<QString, QVariant> lastChallengeResponse = config()->get("LastChallengeResponse").toHash();
|
||||
if (lastChallengeResponse.contains(m_filename)) {
|
||||
m_ui->checkChallengeResponse->setChecked(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DatabaseOpenWidget::noYubikeyFound()
|
||||
{
|
||||
m_ui->buttonRedetectYubikey->setEnabled(true);
|
||||
m_ui->yubikeyProgress->setVisible(false);
|
||||
}
|
||||
|
@ -41,21 +41,27 @@ public:
|
||||
void enterKey(const QString& pw, const QString& keyFile);
|
||||
Database* database();
|
||||
|
||||
Q_SIGNALS:
|
||||
public slots:
|
||||
void pollYubikey();
|
||||
|
||||
signals:
|
||||
void editFinished(bool accepted);
|
||||
|
||||
protected:
|
||||
void showEvent(QShowEvent* event) override;
|
||||
CompositeKey databaseKey();
|
||||
|
||||
protected Q_SLOTS:
|
||||
protected slots:
|
||||
virtual void openDatabase();
|
||||
void reject();
|
||||
|
||||
private Q_SLOTS:
|
||||
private slots:
|
||||
void activatePassword();
|
||||
void activateKeyFile();
|
||||
void activateChallengeResponse();
|
||||
void browseKeyFile();
|
||||
void yubikeyDetected(int slot, bool blocking);
|
||||
void noYubikeyFound();
|
||||
|
||||
protected:
|
||||
const QScopedPointer<Ui::DatabaseOpenWidget> m_ui;
|
||||
|
@ -7,7 +7,7 @@
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>596</width>
|
||||
<height>250</height>
|
||||
<height>302</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout" stretch="0,1,0,1,0,0,3">
|
||||
@ -85,7 +85,7 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<item row="1" column="2">
|
||||
<layout class="QHBoxLayout" name="keyFileLayout">
|
||||
<property name="leftMargin">
|
||||
<number>5</number>
|
||||
@ -118,7 +118,7 @@
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<item row="0" column="2">
|
||||
<layout class="QHBoxLayout" name="passwordLayout">
|
||||
<property name="leftMargin">
|
||||
<number>5</number>
|
||||
@ -142,6 +142,87 @@
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="5" column="2">
|
||||
<layout class="QGridLayout" name="gridLayout_2">
|
||||
<property name="leftMargin">
|
||||
<number>5</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>5</number>
|
||||
</property>
|
||||
<property name="verticalSpacing">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item row="1" column="1">
|
||||
<widget class="QPushButton" name="buttonRedetectYubikey">
|
||||
<property name="enabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Refresh</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QComboBox" name="comboChallengeResponse">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="editable">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QProgressBar" name="yubikeyProgress">
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>16777215</width>
|
||||
<height>2</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>-1</number>
|
||||
</property>
|
||||
<property name="textVisible">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="5" column="0">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<property name="spacing">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>2</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="checkChallengeResponse">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Challenge Response:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
|
@ -50,7 +50,7 @@ void DatabaseRepairWidget::openDatabase()
|
||||
QString errorMsg;
|
||||
if (!key.load(keyFilename, &errorMsg)) {
|
||||
MessageBox::warning(this, tr("Error"), tr("Can't open key file").append(":\n").append(errorMsg));
|
||||
Q_EMIT editFinished(false);
|
||||
emit editFinished(false);
|
||||
return;
|
||||
}
|
||||
masterKey.addKey(key);
|
||||
@ -62,7 +62,7 @@ void DatabaseRepairWidget::openDatabase()
|
||||
if (!file.open(QIODevice::ReadOnly)) {
|
||||
MessageBox::warning(this, tr("Error"), tr("Unable to open the database.").append("\n")
|
||||
.append(file.errorString()));
|
||||
Q_EMIT editFinished(false);
|
||||
emit editFinished(false);
|
||||
return;
|
||||
}
|
||||
if (m_db) {
|
||||
@ -75,21 +75,21 @@ void DatabaseRepairWidget::openDatabase()
|
||||
switch (repairResult) {
|
||||
case KeePass2Repair::NothingTodo:
|
||||
MessageBox::information(this, tr("Error"), tr("Database opened fine. Nothing to do."));
|
||||
Q_EMIT editFinished(false);
|
||||
emit editFinished(false);
|
||||
return;
|
||||
case KeePass2Repair::UnableToOpen:
|
||||
MessageBox::warning(this, tr("Error"), tr("Unable to open the database.").append("\n")
|
||||
.append(repair.errorString()));
|
||||
Q_EMIT editFinished(false);
|
||||
emit editFinished(false);
|
||||
return;
|
||||
case KeePass2Repair::RepairSuccess:
|
||||
m_db = repair.database();
|
||||
MessageBox::warning(this, tr("Success"), tr("The database has been successfully repaired\nYou can now save it."));
|
||||
Q_EMIT editFinished(true);
|
||||
emit editFinished(true);
|
||||
return;
|
||||
case KeePass2Repair::RepairFailed:
|
||||
MessageBox::warning(this, tr("Error"), tr("Unable to repair the database."));
|
||||
Q_EMIT editFinished(false);
|
||||
emit editFinished(false);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -97,9 +97,9 @@ void DatabaseRepairWidget::openDatabase()
|
||||
void DatabaseRepairWidget::processEditFinished(bool result)
|
||||
{
|
||||
if (result) {
|
||||
Q_EMIT success();
|
||||
emit success();
|
||||
}
|
||||
else {
|
||||
Q_EMIT error();
|
||||
emit error();
|
||||
}
|
||||
}
|
||||
|
@ -27,14 +27,14 @@ class DatabaseRepairWidget : public DatabaseOpenWidget
|
||||
public:
|
||||
explicit DatabaseRepairWidget(QWidget* parent = nullptr);
|
||||
|
||||
Q_SIGNALS:
|
||||
signals:
|
||||
void success();
|
||||
void error();
|
||||
|
||||
protected:
|
||||
void openDatabase() override;
|
||||
|
||||
private Q_SLOTS:
|
||||
private slots:
|
||||
void processEditFinished(bool result);
|
||||
};
|
||||
|
||||
|
@ -124,12 +124,12 @@ void DatabaseSettingsWidget::save()
|
||||
truncateHistories();
|
||||
}
|
||||
|
||||
Q_EMIT editFinished(true);
|
||||
emit editFinished(true);
|
||||
}
|
||||
|
||||
void DatabaseSettingsWidget::reject()
|
||||
{
|
||||
Q_EMIT editFinished(false);
|
||||
emit editFinished(false);
|
||||
}
|
||||
|
||||
void DatabaseSettingsWidget::transformRoundsBenchmark()
|
||||
|
@ -38,10 +38,10 @@ public:
|
||||
|
||||
void load(Database* db);
|
||||
|
||||
Q_SIGNALS:
|
||||
signals:
|
||||
void editFinished(bool accepted);
|
||||
|
||||
private Q_SLOTS:
|
||||
private slots:
|
||||
void save();
|
||||
void reject();
|
||||
void transformRoundsBenchmark();
|
||||
|
@ -54,7 +54,7 @@ const int DatabaseTabWidget::LastDatabasesCount = 5;
|
||||
|
||||
DatabaseTabWidget::DatabaseTabWidget(QWidget* parent)
|
||||
: QTabWidget(parent)
|
||||
, m_dbWidgetSateSync(new DatabaseWidgetStateSync(this))
|
||||
, m_dbWidgetStateSync(new DatabaseWidgetStateSync(this))
|
||||
{
|
||||
DragTabBar* tabBar = new DragTabBar(this);
|
||||
setTabBar(tabBar);
|
||||
@ -62,7 +62,7 @@ DatabaseTabWidget::DatabaseTabWidget(QWidget* parent)
|
||||
|
||||
connect(this, SIGNAL(tabCloseRequested(int)), SLOT(closeDatabase(int)));
|
||||
connect(this, SIGNAL(currentChanged(int)), SLOT(emitActivateDatabaseChanged()));
|
||||
connect(this, SIGNAL(activateDatabaseChanged(DatabaseWidget*)), m_dbWidgetSateSync, SLOT(setActive(DatabaseWidget*)));
|
||||
connect(this, SIGNAL(activateDatabaseChanged(DatabaseWidget*)), m_dbWidgetStateSync, SLOT(setActive(DatabaseWidget*)));
|
||||
connect(autoType(), SIGNAL(globalShortcutTriggered()), SLOT(performGlobalAutoType()));
|
||||
}
|
||||
|
||||
@ -120,7 +120,7 @@ void DatabaseTabWidget::openDatabase(const QString& fileName, const QString& pw,
|
||||
QFileInfo fileInfo(fileName);
|
||||
QString canonicalFilePath = fileInfo.canonicalFilePath();
|
||||
if (canonicalFilePath.isEmpty()) {
|
||||
Q_EMIT messageGlobal(tr("File not found!"), MessageWidget::Error);
|
||||
emit messageGlobal(tr("File not found!"), MessageWidget::Error);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -141,7 +141,7 @@ void DatabaseTabWidget::openDatabase(const QString& fileName, const QString& pw,
|
||||
if (!file.open(QIODevice::ReadWrite)) {
|
||||
if (!file.open(QIODevice::ReadOnly)) {
|
||||
// can't open
|
||||
Q_EMIT messageGlobal(
|
||||
emit messageGlobal(
|
||||
tr("Unable to open the database.").append("\n").append(file.errorString()), MessageWidget::Error);
|
||||
return;
|
||||
}
|
||||
@ -198,7 +198,7 @@ void DatabaseTabWidget::openDatabase(const QString& fileName, const QString& pw,
|
||||
insertDatabase(db, dbStruct);
|
||||
|
||||
if (dbStruct.readOnly) {
|
||||
Q_EMIT messageTab(tr("File opened in read only mode."), MessageWidget::Warning);
|
||||
emit messageTab(tr("File opened in read only mode."), MessageWidget::Warning);
|
||||
}
|
||||
|
||||
updateLastDatabases(dbStruct.filePath);
|
||||
@ -209,7 +209,7 @@ void DatabaseTabWidget::openDatabase(const QString& fileName, const QString& pw,
|
||||
else {
|
||||
dbStruct.dbWidget->switchToOpenDatabase(dbStruct.filePath);
|
||||
}
|
||||
Q_EMIT messageDismissGlobal();
|
||||
emit messageDismissGlobal();
|
||||
}
|
||||
|
||||
void DatabaseTabWidget::importCsv()
|
||||
@ -331,7 +331,7 @@ void DatabaseTabWidget::deleteDatabase(Database* db)
|
||||
delete db;
|
||||
|
||||
if (emitDatabaseWithFileClosed) {
|
||||
Q_EMIT databaseWithFileClosed(filePath);
|
||||
emit databaseWithFileClosed(filePath);
|
||||
}
|
||||
}
|
||||
|
||||
@ -348,17 +348,18 @@ bool DatabaseTabWidget::closeAllDatabases()
|
||||
bool DatabaseTabWidget::saveDatabase(Database* db)
|
||||
{
|
||||
DatabaseManagerStruct& dbStruct = m_dbList[db];
|
||||
// temporarily disable autoreload
|
||||
dbStruct.dbWidget->ignoreNextAutoreload();
|
||||
|
||||
if (dbStruct.saveToFilename) {
|
||||
QSaveFile saveFile(dbStruct.canonicalFilePath);
|
||||
if (saveFile.open(QIODevice::WriteOnly)) {
|
||||
// write the database to the file
|
||||
dbStruct.dbWidget->blockAutoReload(true);
|
||||
m_writer.writeDatabase(&saveFile, db);
|
||||
dbStruct.dbWidget->blockAutoReload(false);
|
||||
|
||||
if (m_writer.hasError()) {
|
||||
Q_EMIT messageTab(tr("Writing the database failed.").append("\n")
|
||||
.append(m_writer.errorString()), MessageWidget::Error);
|
||||
emit messageTab(tr("Writing the database failed.").append("\n")
|
||||
.append(m_writer.errorString()), MessageWidget::Error);
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -367,22 +368,19 @@ bool DatabaseTabWidget::saveDatabase(Database* db)
|
||||
dbStruct.modified = false;
|
||||
dbStruct.dbWidget->databaseSaved();
|
||||
updateTabName(db);
|
||||
Q_EMIT messageDismissTab();
|
||||
emit messageDismissTab();
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
Q_EMIT messageTab(tr("Writing the database failed.").append("\n")
|
||||
.append(saveFile.errorString()), MessageWidget::Error);
|
||||
} else {
|
||||
emit messageTab(tr("Writing the database failed.").append("\n")
|
||||
.append(saveFile.errorString()), MessageWidget::Error);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else {
|
||||
Q_EMIT messageTab(tr("Writing the database failed.").append("\n")
|
||||
.append(saveFile.errorString()), MessageWidget::Error);
|
||||
} else {
|
||||
emit messageTab(tr("Writing the database failed.").append("\n")
|
||||
.append(saveFile.errorString()), MessageWidget::Error);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
return saveDatabaseAs(db);
|
||||
}
|
||||
}
|
||||
@ -520,7 +518,7 @@ void DatabaseTabWidget::exportToCsv()
|
||||
|
||||
CsvExporter csvExporter;
|
||||
if (!csvExporter.exportDatabase(fileName, db)) {
|
||||
Q_EMIT messageGlobal(
|
||||
emit messageGlobal(
|
||||
tr("Writing the CSV file failed.").append("\n")
|
||||
.append(csvExporter.errorString()), MessageWidget::Error);
|
||||
}
|
||||
@ -582,7 +580,7 @@ void DatabaseTabWidget::updateTabName(Database* db)
|
||||
}
|
||||
|
||||
setTabText(index, tabName);
|
||||
Q_EMIT tabNameChanged();
|
||||
emit tabNameChanged();
|
||||
}
|
||||
|
||||
void DatabaseTabWidget::updateTabNameFromDbSender()
|
||||
@ -762,7 +760,7 @@ void DatabaseTabWidget::lockDatabases()
|
||||
// database has changed so we can't use the db variable anymore
|
||||
updateTabName(dbWidget->database());
|
||||
|
||||
Q_EMIT databaseLocked(dbWidget);
|
||||
emit databaseLocked(dbWidget);
|
||||
}
|
||||
}
|
||||
|
||||
@ -820,12 +818,12 @@ void DatabaseTabWidget::changeDatabase(Database* newDb, bool unsavedChanges)
|
||||
|
||||
void DatabaseTabWidget::emitActivateDatabaseChanged()
|
||||
{
|
||||
Q_EMIT activateDatabaseChanged(currentDatabaseWidget());
|
||||
emit activateDatabaseChanged(currentDatabaseWidget());
|
||||
}
|
||||
|
||||
void DatabaseTabWidget::emitDatabaseUnlockedFromDbWidgetSender()
|
||||
{
|
||||
Q_EMIT databaseUnlocked(static_cast<DatabaseWidget*>(sender()));
|
||||
emit databaseUnlocked(static_cast<DatabaseWidget*>(sender()));
|
||||
}
|
||||
|
||||
void DatabaseTabWidget::connectDatabase(Database* newDb, Database* oldDb)
|
||||
|
@ -63,7 +63,7 @@ public:
|
||||
|
||||
static const int LastDatabasesCount;
|
||||
|
||||
public Q_SLOTS:
|
||||
public slots:
|
||||
void newDatabase();
|
||||
void openDatabase();
|
||||
void importCsv();
|
||||
@ -81,7 +81,7 @@ public Q_SLOTS:
|
||||
void performGlobalAutoType();
|
||||
void lockDatabases();
|
||||
|
||||
Q_SIGNALS:
|
||||
signals:
|
||||
void tabNameChanged();
|
||||
void databaseWithFileClosed(QString filePath);
|
||||
void activateDatabaseChanged(DatabaseWidget* dbWidget);
|
||||
@ -92,7 +92,7 @@ Q_SIGNALS:
|
||||
void messageDismissGlobal();
|
||||
void messageDismissTab();
|
||||
|
||||
private Q_SLOTS:
|
||||
private slots:
|
||||
void updateTabName(Database* db);
|
||||
void updateTabNameFromDbSender();
|
||||
void updateTabNameFromDbWidgetSender();
|
||||
@ -117,7 +117,7 @@ private:
|
||||
|
||||
KeePass2Writer m_writer;
|
||||
QHash<Database*, DatabaseManagerStruct> m_dbList;
|
||||
DatabaseWidgetStateSync* m_dbWidgetSateSync;
|
||||
DatabaseWidgetStateSync* m_dbWidgetStateSync;
|
||||
};
|
||||
|
||||
#endif // KEEPASSX_DATABASETABWIDGET_H
|
||||
|
@ -173,14 +173,14 @@ DatabaseWidget::DatabaseWidget(Database* db, QWidget* parent)
|
||||
connect(m_unlockDatabaseDialog, SIGNAL(unlockDone(bool)), SLOT(unlockDatabase(bool)));
|
||||
connect(&m_fileWatcher, SIGNAL(fileChanged(QString)), this, SLOT(onWatchedFileChanged()));
|
||||
connect(&m_fileWatchTimer, SIGNAL(timeout()), this, SLOT(reloadDatabaseFile()));
|
||||
connect(&m_ignoreWatchTimer, SIGNAL(timeout()), this, SLOT(onWatchedFileChanged()));
|
||||
connect(&m_fileWatchUnblockTimer, SIGNAL(timeout()), this, SLOT(unblockAutoReload()));
|
||||
connect(this, SIGNAL(currentChanged(int)), this, SLOT(emitCurrentModeChanged()));
|
||||
|
||||
m_databaseModified = false;
|
||||
|
||||
m_fileWatchTimer.setSingleShot(true);
|
||||
m_ignoreWatchTimer.setSingleShot(true);
|
||||
m_ignoreNextAutoreload = false;
|
||||
m_fileWatchUnblockTimer.setSingleShot(true);
|
||||
m_ignoreAutoReload = false;
|
||||
|
||||
m_searchCaseSensitive = false;
|
||||
|
||||
@ -270,7 +270,7 @@ void DatabaseWidget::clearAllWidgets()
|
||||
|
||||
void DatabaseWidget::emitCurrentModeChanged()
|
||||
{
|
||||
Q_EMIT currentModeChanged(currentMode());
|
||||
emit currentModeChanged(currentMode());
|
||||
}
|
||||
|
||||
Database* DatabaseWidget::database()
|
||||
@ -316,7 +316,7 @@ void DatabaseWidget::replaceDatabase(Database* db)
|
||||
Database* oldDb = m_db;
|
||||
m_db = db;
|
||||
m_groupView->changeDatabase(m_db);
|
||||
Q_EMIT databaseChanged(m_db, m_databaseModified);
|
||||
emit databaseChanged(m_db, m_databaseModified);
|
||||
delete oldDb;
|
||||
}
|
||||
|
||||
@ -414,7 +414,7 @@ void DatabaseWidget::copyTitle()
|
||||
return;
|
||||
}
|
||||
|
||||
setClipboardTextAndMinimize(currentEntry->resolvePlaceholder(currentEntry->title()));
|
||||
setClipboardTextAndMinimize(currentEntry->resolveMultiplePlaceholders(currentEntry->title()));
|
||||
}
|
||||
|
||||
void DatabaseWidget::copyUsername()
|
||||
@ -425,7 +425,7 @@ void DatabaseWidget::copyUsername()
|
||||
return;
|
||||
}
|
||||
|
||||
setClipboardTextAndMinimize(currentEntry->resolvePlaceholder(currentEntry->username()));
|
||||
setClipboardTextAndMinimize(currentEntry->resolveMultiplePlaceholders(currentEntry->username()));
|
||||
}
|
||||
|
||||
void DatabaseWidget::copyPassword()
|
||||
@ -436,7 +436,7 @@ void DatabaseWidget::copyPassword()
|
||||
return;
|
||||
}
|
||||
|
||||
setClipboardTextAndMinimize(currentEntry->resolvePlaceholder(currentEntry->password()));
|
||||
setClipboardTextAndMinimize(currentEntry->resolveMultiplePlaceholders(currentEntry->password()));
|
||||
}
|
||||
|
||||
void DatabaseWidget::copyURL()
|
||||
@ -447,7 +447,7 @@ void DatabaseWidget::copyURL()
|
||||
return;
|
||||
}
|
||||
|
||||
setClipboardTextAndMinimize(currentEntry->resolvePlaceholder(currentEntry->url()));
|
||||
setClipboardTextAndMinimize(currentEntry->resolveMultiplePlaceholders(currentEntry->url()));
|
||||
}
|
||||
|
||||
void DatabaseWidget::copyNotes()
|
||||
@ -458,7 +458,7 @@ void DatabaseWidget::copyNotes()
|
||||
return;
|
||||
}
|
||||
|
||||
setClipboardTextAndMinimize(currentEntry->resolvePlaceholder(currentEntry->notes()));
|
||||
setClipboardTextAndMinimize(currentEntry->resolveMultiplePlaceholders(currentEntry->notes()));
|
||||
}
|
||||
|
||||
void DatabaseWidget::copyAttribute(QAction* action)
|
||||
@ -469,7 +469,7 @@ void DatabaseWidget::copyAttribute(QAction* action)
|
||||
return;
|
||||
}
|
||||
|
||||
setClipboardTextAndMinimize(currentEntry->attributes()->value(action->text()));
|
||||
setClipboardTextAndMinimize(currentEntry->resolveMultiplePlaceholders(currentEntry->attributes()->value(action->text())));
|
||||
}
|
||||
|
||||
void DatabaseWidget::setClipboardTextAndMinimize(const QString& text)
|
||||
@ -717,7 +717,7 @@ void DatabaseWidget::updateMasterKey(bool accepted)
|
||||
}
|
||||
}
|
||||
else if (!m_db->hasKey()) {
|
||||
Q_EMIT closeRequest();
|
||||
emit closeRequest();
|
||||
return;
|
||||
}
|
||||
|
||||
@ -729,7 +729,7 @@ void DatabaseWidget::openDatabase(bool accepted)
|
||||
if (accepted) {
|
||||
replaceDatabase(static_cast<DatabaseOpenWidget*>(sender())->database());
|
||||
setCurrentWidget(m_mainWidget);
|
||||
Q_EMIT unlockedDatabase();
|
||||
emit unlockedDatabase();
|
||||
|
||||
// We won't need those anymore and KeePass1OpenWidget closes
|
||||
// the file in its dtor.
|
||||
@ -744,7 +744,7 @@ void DatabaseWidget::openDatabase(bool accepted)
|
||||
if (m_databaseOpenWidget->database()) {
|
||||
delete m_databaseOpenWidget->database();
|
||||
}
|
||||
Q_EMIT closeRequest();
|
||||
emit closeRequest();
|
||||
}
|
||||
}
|
||||
|
||||
@ -767,13 +767,13 @@ void DatabaseWidget::mergeDatabase(bool accepted)
|
||||
}
|
||||
|
||||
setCurrentWidget(m_mainWidget);
|
||||
Q_EMIT databaseMerged(m_db);
|
||||
emit databaseMerged(m_db);
|
||||
}
|
||||
|
||||
void DatabaseWidget::unlockDatabase(bool accepted)
|
||||
{
|
||||
if (!accepted) {
|
||||
Q_EMIT closeRequest();
|
||||
emit closeRequest();
|
||||
return;
|
||||
}
|
||||
|
||||
@ -792,7 +792,7 @@ void DatabaseWidget::unlockDatabase(bool accepted)
|
||||
|
||||
setCurrentWidget(m_mainWidget);
|
||||
m_unlockDatabaseWidget->clearForms();
|
||||
Q_EMIT unlockedDatabase();
|
||||
emit unlockedDatabase();
|
||||
|
||||
if (sender() == m_unlockDatabaseDialog) {
|
||||
QList<Database*> dbList;
|
||||
@ -914,7 +914,7 @@ void DatabaseWidget::search(const QString& searchtext)
|
||||
return;
|
||||
}
|
||||
|
||||
Q_EMIT searchModeAboutToActivate();
|
||||
emit searchModeAboutToActivate();
|
||||
|
||||
Qt::CaseSensitivity caseSensitive = m_searchCaseSensitive ? Qt::CaseSensitive : Qt::CaseInsensitive;
|
||||
|
||||
@ -933,7 +933,7 @@ void DatabaseWidget::search(const QString& searchtext)
|
||||
|
||||
m_searchingLabel->setVisible(true);
|
||||
|
||||
Q_EMIT searchModeActivated();
|
||||
emit searchModeActivated();
|
||||
}
|
||||
|
||||
void DatabaseWidget::setSearchCaseSensitive(bool state)
|
||||
@ -960,12 +960,12 @@ void DatabaseWidget::endSearch()
|
||||
{
|
||||
if (isInSearchMode())
|
||||
{
|
||||
Q_EMIT listModeAboutToActivate();
|
||||
emit listModeAboutToActivate();
|
||||
|
||||
// Show the normal entry view of the current group
|
||||
m_entryView->setGroup(currentGroup());
|
||||
|
||||
Q_EMIT listModeActivated();
|
||||
emit listModeActivated();
|
||||
}
|
||||
|
||||
m_searchingLabel->setVisible(false);
|
||||
@ -976,12 +976,12 @@ void DatabaseWidget::endSearch()
|
||||
|
||||
void DatabaseWidget::emitGroupContextMenuRequested(const QPoint& pos)
|
||||
{
|
||||
Q_EMIT groupContextMenuRequested(m_groupView->viewport()->mapToGlobal(pos));
|
||||
emit groupContextMenuRequested(m_groupView->viewport()->mapToGlobal(pos));
|
||||
}
|
||||
|
||||
void DatabaseWidget::emitEntryContextMenuRequested(const QPoint& pos)
|
||||
{
|
||||
Q_EMIT entryContextMenuRequested(m_entryView->viewport()->mapToGlobal(pos));
|
||||
emit entryContextMenuRequested(m_entryView->viewport()->mapToGlobal(pos));
|
||||
}
|
||||
|
||||
bool DatabaseWidget::dbHasKey() const
|
||||
@ -1030,7 +1030,7 @@ void DatabaseWidget::lock()
|
||||
|
||||
void DatabaseWidget::updateFilename(const QString& fileName)
|
||||
{
|
||||
if (! m_filename.isEmpty()) {
|
||||
if (!m_filename.isEmpty()) {
|
||||
m_fileWatcher.removePath(m_filename);
|
||||
}
|
||||
|
||||
@ -1038,26 +1038,31 @@ void DatabaseWidget::updateFilename(const QString& fileName)
|
||||
m_filename = fileName;
|
||||
}
|
||||
|
||||
void DatabaseWidget::ignoreNextAutoreload()
|
||||
void DatabaseWidget::blockAutoReload(bool block)
|
||||
{
|
||||
m_ignoreNextAutoreload = true;
|
||||
m_ignoreWatchTimer.start(100);
|
||||
if (block) {
|
||||
m_ignoreAutoReload = true;
|
||||
m_fileWatchTimer.stop();
|
||||
} else {
|
||||
m_fileWatchUnblockTimer.start(500);
|
||||
}
|
||||
}
|
||||
|
||||
void DatabaseWidget::unblockAutoReload()
|
||||
{
|
||||
m_ignoreAutoReload = false;
|
||||
updateFilename(m_filename);
|
||||
}
|
||||
|
||||
void DatabaseWidget::onWatchedFileChanged()
|
||||
{
|
||||
if (m_ignoreNextAutoreload) {
|
||||
// Reset the watch
|
||||
m_ignoreNextAutoreload = false;
|
||||
m_ignoreWatchTimer.stop();
|
||||
m_fileWatcher.addPath(m_filename);
|
||||
if (m_ignoreAutoReload) {
|
||||
return;
|
||||
}
|
||||
else {
|
||||
if (m_fileWatchTimer.isActive())
|
||||
return;
|
||||
if (m_fileWatchTimer.isActive())
|
||||
return;
|
||||
|
||||
m_fileWatchTimer.start(500);
|
||||
}
|
||||
m_fileWatchTimer.start(500);
|
||||
}
|
||||
|
||||
void DatabaseWidget::reloadDatabaseFile()
|
||||
@ -1197,7 +1202,7 @@ bool DatabaseWidget::currentEntryHasUsername()
|
||||
Q_ASSERT(false);
|
||||
return false;
|
||||
}
|
||||
return !currentEntry->resolvePlaceholder(currentEntry->username()).isEmpty();
|
||||
return !currentEntry->resolveMultiplePlaceholders(currentEntry->username()).isEmpty();
|
||||
}
|
||||
|
||||
bool DatabaseWidget::currentEntryHasPassword()
|
||||
@ -1207,7 +1212,7 @@ bool DatabaseWidget::currentEntryHasPassword()
|
||||
Q_ASSERT(false);
|
||||
return false;
|
||||
}
|
||||
return !currentEntry->resolvePlaceholder(currentEntry->password()).isEmpty();
|
||||
return !currentEntry->resolveMultiplePlaceholders(currentEntry->password()).isEmpty();
|
||||
}
|
||||
|
||||
bool DatabaseWidget::currentEntryHasUrl()
|
||||
@ -1217,7 +1222,7 @@ bool DatabaseWidget::currentEntryHasUrl()
|
||||
Q_ASSERT(false);
|
||||
return false;
|
||||
}
|
||||
return !currentEntry->resolvePlaceholder(currentEntry->url()).isEmpty();
|
||||
return !currentEntry->resolveMultiplePlaceholders(currentEntry->url()).isEmpty();
|
||||
}
|
||||
|
||||
bool DatabaseWidget::currentEntryHasNotes()
|
||||
@ -1227,7 +1232,7 @@ bool DatabaseWidget::currentEntryHasNotes()
|
||||
Q_ASSERT(false);
|
||||
return false;
|
||||
}
|
||||
return !currentEntry->resolvePlaceholder(currentEntry->notes()).isEmpty();
|
||||
return !currentEntry->resolveMultiplePlaceholders(currentEntry->notes()).isEmpty();
|
||||
}
|
||||
|
||||
GroupView* DatabaseWidget::groupView() {
|
||||
|
@ -100,10 +100,10 @@ public:
|
||||
EntryView* entryView();
|
||||
void showUnlockDialog();
|
||||
void closeUnlockDialog();
|
||||
void ignoreNextAutoreload();
|
||||
void blockAutoReload(bool block = true);
|
||||
void refreshSearch();
|
||||
|
||||
Q_SIGNALS:
|
||||
signals:
|
||||
void closeRequest();
|
||||
void currentModeChanged(DatabaseWidget::Mode mode);
|
||||
void groupChanged();
|
||||
@ -121,7 +121,7 @@ Q_SIGNALS:
|
||||
void entryColumnSizesChanged();
|
||||
void updateSearch(QString text);
|
||||
|
||||
public Q_SLOTS:
|
||||
public slots:
|
||||
void createEntry();
|
||||
void cloneEntry();
|
||||
void deleteEntries();
|
||||
@ -161,7 +161,7 @@ public Q_SLOTS:
|
||||
void showMessage(const QString& text, MessageWidget::MessageType type);
|
||||
void hideMessage();
|
||||
|
||||
private Q_SLOTS:
|
||||
private slots:
|
||||
void entryActivationSignalReceived(Entry* entry, EntryModel::ModelColumn column);
|
||||
void switchBackToEntryEdit();
|
||||
void switchToHistoryView(Entry* entry);
|
||||
@ -179,6 +179,7 @@ private Q_SLOTS:
|
||||
void onWatchedFileChanged();
|
||||
void reloadDatabaseFile();
|
||||
void restoreGroupEntryFocus(Uuid groupUuid, Uuid EntryUuid);
|
||||
void unblockAutoReload();
|
||||
|
||||
private:
|
||||
void setClipboardTextAndMinimize(const QString& text);
|
||||
@ -217,8 +218,8 @@ private:
|
||||
// Autoreload
|
||||
QFileSystemWatcher m_fileWatcher;
|
||||
QTimer m_fileWatchTimer;
|
||||
bool m_ignoreNextAutoreload;
|
||||
QTimer m_ignoreWatchTimer;
|
||||
QTimer m_fileWatchUnblockTimer;
|
||||
bool m_ignoreAutoReload;
|
||||
bool m_databaseModified;
|
||||
};
|
||||
|
||||
|
@ -29,12 +29,12 @@ public:
|
||||
explicit DatabaseWidgetStateSync(QObject* parent = nullptr);
|
||||
~DatabaseWidgetStateSync();
|
||||
|
||||
public Q_SLOTS:
|
||||
public slots:
|
||||
void setActive(DatabaseWidget* dbWidget);
|
||||
void restoreListView();
|
||||
void restoreSearchView();
|
||||
|
||||
private Q_SLOTS:
|
||||
private slots:
|
||||
void blockUpdates();
|
||||
void updateSplitterSizes();
|
||||
void updateColumnSizes();
|
||||
|
@ -34,7 +34,7 @@ protected:
|
||||
void dropEvent(QDropEvent* event) override;
|
||||
void tabLayoutChange() override;
|
||||
|
||||
private Q_SLOTS:
|
||||
private slots:
|
||||
void dragSwitchTab();
|
||||
|
||||
private:
|
||||
|
@ -48,9 +48,9 @@ EditWidgetIcons::EditWidgetIcons(QWidget* parent)
|
||||
, m_defaultIconModel(new DefaultIconModel(this))
|
||||
, m_customIconModel(new CustomIconModel(this))
|
||||
#ifdef WITH_XC_HTTP
|
||||
, m_httpClient(nullptr)
|
||||
, m_fallbackToGoogle(true)
|
||||
, m_redirectCount(0)
|
||||
, m_httpClient(nullptr)
|
||||
#endif
|
||||
{
|
||||
m_ui->setupUi(this);
|
||||
@ -149,6 +149,7 @@ void EditWidgetIcons::setUrl(const QString& url)
|
||||
m_ui->faviconButton->setVisible(!url.isEmpty());
|
||||
resetFaviconDownload();
|
||||
#else
|
||||
Q_UNUSED(url);
|
||||
m_ui->faviconButton->setVisible(false);
|
||||
#endif
|
||||
}
|
||||
@ -275,7 +276,7 @@ void EditWidgetIcons::addCustomIcon()
|
||||
m_ui->customIconsView->setCurrentIndex(index);
|
||||
}
|
||||
else {
|
||||
Q_EMIT messageEditEntry(tr("Can't read icon"), MessageWidget::Error);
|
||||
emit messageEditEntry(tr("Can't read icon"), MessageWidget::Error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -63,14 +63,14 @@ public:
|
||||
void reset();
|
||||
void load(const Uuid& currentUuid, Database* database, const IconStruct& iconStruct, const QString& url = "");
|
||||
|
||||
public Q_SLOTS:
|
||||
public slots:
|
||||
void setUrl(const QString& url);
|
||||
|
||||
Q_SIGNALS:
|
||||
signals:
|
||||
void messageEditEntry(QString, MessageWidget::MessageType);
|
||||
void messageEditEntryDismiss();
|
||||
|
||||
private Q_SLOTS:
|
||||
private slots:
|
||||
void downloadFavicon();
|
||||
#ifdef WITH_XC_HTTP
|
||||
void fetchFavicon(const QUrl& url);
|
||||
|
@ -21,6 +21,7 @@
|
||||
#include "KMessageWidget.h"
|
||||
|
||||
#include "core/FilePath.h"
|
||||
#include "core/Global.h"
|
||||
|
||||
#include <QAction>
|
||||
#include <QEvent>
|
||||
@ -117,7 +118,8 @@ void KMessageWidgetPrivate::createLayout()
|
||||
qDeleteAll(buttons);
|
||||
buttons.clear();
|
||||
|
||||
Q_FOREACH (QAction *action, q->actions()) {
|
||||
const auto actions = q->actions();
|
||||
for (QAction *action: actions) {
|
||||
QToolButton *button = new QToolButton(content);
|
||||
button->setDefaultAction(action);
|
||||
button->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
|
||||
@ -137,7 +139,7 @@ void KMessageWidgetPrivate::createLayout()
|
||||
|
||||
QHBoxLayout *buttonLayout = new QHBoxLayout;
|
||||
buttonLayout->addStretch();
|
||||
Q_FOREACH (QToolButton *button, buttons) {
|
||||
for (QToolButton* button: asConst(buttons)) {
|
||||
// For some reason, calling show() is necessary if wordwrap is true,
|
||||
// otherwise the buttons do not show up. It is not needed if
|
||||
// wordwrap is false.
|
||||
@ -151,7 +153,7 @@ void KMessageWidgetPrivate::createLayout()
|
||||
layout->addWidget(iconLabel);
|
||||
layout->addWidget(textLabel);
|
||||
|
||||
Q_FOREACH (QToolButton *button, buttons) {
|
||||
for (QToolButton* button: asConst(buttons)) {
|
||||
layout->addWidget(button);
|
||||
}
|
||||
|
||||
|
@ -224,7 +224,7 @@ public:
|
||||
*/
|
||||
bool isShowAnimationRunning() const;
|
||||
|
||||
public Q_SLOTS:
|
||||
public slots:
|
||||
/**
|
||||
* Set the text of the message widget to @p text.
|
||||
* If the message widget is already visible, the text changes on the fly.
|
||||
@ -277,7 +277,7 @@ public Q_SLOTS:
|
||||
*/
|
||||
void setIcon(const QIcon &icon);
|
||||
|
||||
Q_SIGNALS:
|
||||
signals:
|
||||
/**
|
||||
* This signal is emitted when the user clicks a link in the text label.
|
||||
* The URL referred to by the href anchor is passed in contents.
|
||||
|
@ -62,7 +62,7 @@ void KeePass1OpenWidget::openDatabase()
|
||||
|
||||
if (m_db) {
|
||||
m_db->metadata()->setName(QFileInfo(m_filename).completeBaseName());
|
||||
Q_EMIT editFinished(true);
|
||||
emit editFinished(true);
|
||||
}
|
||||
else {
|
||||
m_ui->messageWidget->showMessage(tr("Unable to open the database.").append("\n")
|
||||
|
@ -34,7 +34,7 @@ public:
|
||||
protected:
|
||||
void resizeEvent(QResizeEvent* event) override;
|
||||
|
||||
private Q_SLOTS:
|
||||
private slots:
|
||||
void updateCloseButton(const QString& text);
|
||||
|
||||
private:
|
||||
|
@ -874,13 +874,15 @@ bool MainWindow::isTrayIconEnabled() const
|
||||
#endif
|
||||
}
|
||||
|
||||
void MainWindow::displayGlobalMessage(const QString& text, MessageWidget::MessageType type)
|
||||
void MainWindow::displayGlobalMessage(const QString& text, MessageWidget::MessageType type, bool showClosebutton)
|
||||
{
|
||||
m_ui->globalMessageWidget->setCloseButtonVisible(showClosebutton);
|
||||
m_ui->globalMessageWidget->showMessage(text, type);
|
||||
}
|
||||
|
||||
void MainWindow::displayTabMessage(const QString& text, MessageWidget::MessageType type)
|
||||
void MainWindow::displayTabMessage(const QString& text, MessageWidget::MessageType type, bool showClosebutton)
|
||||
{
|
||||
m_ui->globalMessageWidget->setCloseButtonVisible(showClosebutton);
|
||||
m_ui->tabWidget->currentDatabaseWidget()->showMessage(text, type);
|
||||
}
|
||||
|
||||
@ -896,3 +898,14 @@ void MainWindow::hideTabMessage()
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::showYubiKeyPopup()
|
||||
{
|
||||
displayGlobalMessage(tr("Please touch the button on your YubiKey!"), MessageWidget::Information, false);
|
||||
setEnabled(false);
|
||||
}
|
||||
|
||||
void MainWindow::hideYubiKeyPopup()
|
||||
{
|
||||
hideGlobalMessage();
|
||||
setEnabled(true);
|
||||
}
|
||||
|
@ -24,6 +24,7 @@
|
||||
|
||||
#include "core/SignalMultiplexer.h"
|
||||
#include "gui/DatabaseWidget.h"
|
||||
#include "gui/Application.h"
|
||||
|
||||
namespace Ui {
|
||||
class MainWindow;
|
||||
@ -39,16 +40,21 @@ public:
|
||||
MainWindow();
|
||||
~MainWindow();
|
||||
|
||||
public Q_SLOTS:
|
||||
public slots:
|
||||
void openDatabase(const QString& fileName, const QString& pw = QString(),
|
||||
const QString& keyFile = QString());
|
||||
void appExit();
|
||||
void displayGlobalMessage(const QString& text, MessageWidget::MessageType type, bool showClosebutton = true);
|
||||
void displayTabMessage(const QString& text, MessageWidget::MessageType type, bool showClosebutton = true);
|
||||
void hideGlobalMessage();
|
||||
void showYubiKeyPopup();
|
||||
void hideYubiKeyPopup();
|
||||
|
||||
protected:
|
||||
void closeEvent(QCloseEvent* event) override;
|
||||
void changeEvent(QEvent* event) override;
|
||||
|
||||
private Q_SLOTS:
|
||||
private slots:
|
||||
void setMenuActionState(DatabaseWidget::Mode mode = DatabaseWidget::None);
|
||||
void updateWindowTitle();
|
||||
void showAboutDialog();
|
||||
@ -76,9 +82,6 @@ private Q_SLOTS:
|
||||
void toggleWindow();
|
||||
void lockDatabasesAfterInactivity();
|
||||
void repairDatabase();
|
||||
void displayGlobalMessage(const QString& text, MessageWidget::MessageType type);
|
||||
void displayTabMessage(const QString& text, MessageWidget::MessageType type);
|
||||
void hideGlobalMessage();
|
||||
void hideTabMessage();
|
||||
|
||||
private:
|
||||
@ -107,4 +110,7 @@ private:
|
||||
bool appExitCalled;
|
||||
};
|
||||
|
||||
#define KEEPASSXC_MAIN_WINDOW (qobject_cast<Application*>(qApp) ? \
|
||||
qobject_cast<MainWindow*>(qobject_cast<Application*>(qApp)->mainWindow()) : nullptr)
|
||||
|
||||
#endif // KEEPASSX_MAINWINDOW_H
|
||||
|
@ -123,9 +123,7 @@
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="WelcomeWidget" name="welcomeWidget" native="true">
|
||||
<zorder>horizontalSpacer_2</zorder>
|
||||
</widget>
|
||||
<widget class="WelcomeWidget" name="welcomeWidget" native="true"/>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer_2">
|
||||
|
@ -27,7 +27,7 @@ class MessageWidget : public KMessageWidget
|
||||
public:
|
||||
explicit MessageWidget(QWidget* parent = 0);
|
||||
|
||||
public Q_SLOTS:
|
||||
public slots:
|
||||
void showMessage(const QString& text, MessageWidget::MessageType type);
|
||||
void hideMessage();
|
||||
|
||||
|
@ -35,7 +35,7 @@ public:
|
||||
void setNumberAlternatives(int alternatives);
|
||||
void showPopup();
|
||||
|
||||
public Q_SLOTS:
|
||||
public slots:
|
||||
void setEcho(bool echo);
|
||||
|
||||
private:
|
||||
|
@ -69,7 +69,7 @@ void PasswordEdit::setShowPassword(bool show)
|
||||
}
|
||||
}
|
||||
updateStylesheet();
|
||||
Q_EMIT showPasswordChanged(show);
|
||||
emit showPasswordChanged(show);
|
||||
}
|
||||
|
||||
bool PasswordEdit::passwordsEqual() const
|
||||
|
@ -31,13 +31,13 @@ public:
|
||||
explicit PasswordEdit(QWidget* parent = nullptr);
|
||||
void enableVerifyMode(PasswordEdit* baseEdit);
|
||||
|
||||
public Q_SLOTS:
|
||||
public slots:
|
||||
void setShowPassword(bool show);
|
||||
|
||||
Q_SIGNALS:
|
||||
signals:
|
||||
void showPasswordChanged(bool show);
|
||||
|
||||
private Q_SLOTS:
|
||||
private slots:
|
||||
void updateStylesheet();
|
||||
void autocompletePassword(QString password);
|
||||
|
||||
|
@ -145,8 +145,8 @@ void PasswordGeneratorWidget::generatePassword()
|
||||
void PasswordGeneratorWidget::applyPassword()
|
||||
{
|
||||
saveSettings();
|
||||
Q_EMIT appliedPassword(m_ui->editNewPassword->text());
|
||||
Q_EMIT dialogTerminated();
|
||||
emit appliedPassword(m_ui->editNewPassword->text());
|
||||
emit dialogTerminated();
|
||||
}
|
||||
|
||||
void PasswordGeneratorWidget::sliderMoved()
|
||||
|
@ -43,11 +43,11 @@ public:
|
||||
void setStandaloneMode(bool standalone);
|
||||
void regeneratePassword();
|
||||
|
||||
Q_SIGNALS:
|
||||
signals:
|
||||
void appliedPassword(const QString& password);
|
||||
void dialogTerminated();
|
||||
|
||||
private Q_SLOTS:
|
||||
private slots:
|
||||
void applyPassword();
|
||||
void generatePassword();
|
||||
void updateApplyEnabled(const QString& password);
|
||||
|
@ -23,6 +23,7 @@
|
||||
#include "core/Config.h"
|
||||
#include "core/Translator.h"
|
||||
#include "core/FilePath.h"
|
||||
#include "core/Global.h"
|
||||
|
||||
class SettingsWidget::ExtraPage
|
||||
{
|
||||
@ -144,8 +145,9 @@ void SettingsWidget::loadSettings()
|
||||
m_secUi->passwordRepeatCheckBox->setChecked(config()->get("security/passwordsrepeat").toBool());
|
||||
|
||||
|
||||
Q_FOREACH (const ExtraPage& page, m_extraPages)
|
||||
for (const ExtraPage& page: asConst(m_extraPages)) {
|
||||
page.loadSettings();
|
||||
}
|
||||
|
||||
setCurrentPage(0);
|
||||
}
|
||||
@ -190,10 +192,11 @@ void SettingsWidget::saveSettings()
|
||||
config()->set("security/passwordscleartext", m_secUi->passwordCleartextCheckBox->isChecked());
|
||||
config()->set("security/passwordsrepeat", m_secUi->passwordRepeatCheckBox->isChecked());
|
||||
|
||||
Q_FOREACH (const ExtraPage& page, m_extraPages)
|
||||
for (const ExtraPage& page: asConst(m_extraPages)) {
|
||||
page.saveSettings();
|
||||
}
|
||||
|
||||
Q_EMIT editFinished(true);
|
||||
emit editFinished(true);
|
||||
}
|
||||
|
||||
void SettingsWidget::reject()
|
||||
@ -203,7 +206,7 @@ void SettingsWidget::reject()
|
||||
autoType()->registerGlobalShortcut(m_globalAutoTypeKey, m_globalAutoTypeModifiers);
|
||||
}
|
||||
|
||||
Q_EMIT editFinished(false);
|
||||
emit editFinished(false);
|
||||
}
|
||||
|
||||
void SettingsWidget::enableAutoSaveOnExit(bool checked)
|
||||
|
@ -45,10 +45,10 @@ public:
|
||||
void addSettingsPage(ISettingsPage * page);
|
||||
void loadSettings();
|
||||
|
||||
Q_SIGNALS:
|
||||
signals:
|
||||
void editFinished(bool accepted);
|
||||
|
||||
private Q_SLOTS:
|
||||
private slots:
|
||||
void saveSettings();
|
||||
void reject();
|
||||
void enableAutoSaveOnExit(bool checked);
|
||||
|
@ -49,7 +49,7 @@ void UnlockDatabaseDialog::complete(bool r)
|
||||
{
|
||||
if (r) {
|
||||
accept();
|
||||
Q_EMIT unlockDone(true);
|
||||
emit unlockDone(true);
|
||||
} else {
|
||||
reject();
|
||||
}
|
||||
|
@ -36,10 +36,10 @@ public:
|
||||
void clearForms();
|
||||
Database* database();
|
||||
|
||||
Q_SIGNALS:
|
||||
signals:
|
||||
void unlockDone(bool);
|
||||
|
||||
public Q_SLOTS:
|
||||
public slots:
|
||||
void complete(bool r);
|
||||
|
||||
private:
|
||||
|
@ -33,6 +33,7 @@ void UnlockDatabaseWidget::clearForms()
|
||||
m_ui->comboKeyFile->clear();
|
||||
m_ui->checkPassword->setChecked(false);
|
||||
m_ui->checkKeyFile->setChecked(false);
|
||||
m_ui->checkChallengeResponse->setChecked(false);
|
||||
m_ui->buttonTogglePassword->setChecked(false);
|
||||
m_db = nullptr;
|
||||
}
|
||||
|
@ -64,5 +64,5 @@ void WelcomeWidget::openDatabaseFromFile(QListWidgetItem* item)
|
||||
if (item->text().isEmpty()) {
|
||||
return;
|
||||
}
|
||||
Q_EMIT openDatabaseFile(item->text());
|
||||
emit openDatabaseFile(item->text());
|
||||
}
|
@ -33,13 +33,13 @@ public:
|
||||
explicit WelcomeWidget(QWidget* parent = nullptr);
|
||||
~WelcomeWidget();
|
||||
|
||||
Q_SIGNALS:
|
||||
signals:
|
||||
void newDatabase();
|
||||
void openDatabase();
|
||||
void openDatabaseFile(QString);
|
||||
void importKeePass1Database();
|
||||
|
||||
private Q_SLOTS:
|
||||
private slots:
|
||||
void openDatabaseFromFile(QListWidgetItem* item);
|
||||
|
||||
private:
|
||||
|
@ -103,7 +103,7 @@ QVariant AutoTypeAssociationsModel::data(const QModelIndex& index, int role) con
|
||||
|
||||
void AutoTypeAssociationsModel::associationChange(int i)
|
||||
{
|
||||
Q_EMIT dataChanged(index(i, 0), index(i, columnCount() - 1));
|
||||
emit dataChanged(index(i, 0), index(i, columnCount() - 1));
|
||||
}
|
||||
|
||||
void AutoTypeAssociationsModel::associationAboutToAdd(int i)
|
||||
|
@ -36,7 +36,7 @@ public:
|
||||
QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override;
|
||||
QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override;
|
||||
|
||||
public Q_SLOTS:
|
||||
public slots:
|
||||
void associationChange(int i);
|
||||
void associationAboutToAdd(int i);
|
||||
void associationAdd();
|
||||
|
@ -212,7 +212,7 @@ void EditEntryWidget::emitHistoryEntryActivated(const QModelIndex& index)
|
||||
Q_ASSERT(!m_history);
|
||||
|
||||
Entry* entry = m_historyModel->entryFromIndex(index);
|
||||
Q_EMIT historyEntryActivated(entry);
|
||||
emit historyEntryActivated(entry);
|
||||
}
|
||||
|
||||
void EditEntryWidget::histEntryActivated(const QModelIndex& index)
|
||||
@ -407,7 +407,7 @@ void EditEntryWidget::saveEntry()
|
||||
if (m_history) {
|
||||
clear();
|
||||
hideMessage();
|
||||
Q_EMIT editFinished(false);
|
||||
emit editFinished(false);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -442,7 +442,7 @@ void EditEntryWidget::saveEntry()
|
||||
|
||||
clear();
|
||||
|
||||
Q_EMIT editFinished(true);
|
||||
emit editFinished(true);
|
||||
}
|
||||
|
||||
void EditEntryWidget::updateEntryData(Entry* entry) const
|
||||
@ -487,7 +487,7 @@ void EditEntryWidget::cancel()
|
||||
if (m_history) {
|
||||
clear();
|
||||
hideMessage();
|
||||
Q_EMIT editFinished(false);
|
||||
emit editFinished(false);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -498,7 +498,7 @@ void EditEntryWidget::cancel()
|
||||
|
||||
clear();
|
||||
|
||||
Q_EMIT editFinished(false);
|
||||
emit editFinished(false);
|
||||
}
|
||||
|
||||
void EditEntryWidget::clear()
|
||||
|
@ -63,11 +63,11 @@ public:
|
||||
void clear();
|
||||
bool hasBeenModified() const;
|
||||
|
||||
Q_SIGNALS:
|
||||
signals:
|
||||
void editFinished(bool accepted);
|
||||
void historyEntryActivated(Entry* entry);
|
||||
|
||||
private Q_SLOTS:
|
||||
private slots:
|
||||
void saveEntry();
|
||||
void cancel();
|
||||
void togglePasswordGeneratorButton(bool checked);
|
||||
|
@ -259,11 +259,6 @@
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
<zorder></zorder>
|
||||
<zorder></zorder>
|
||||
<zorder></zorder>
|
||||
<zorder></zorder>
|
||||
<zorder></zorder>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
|
@ -97,7 +97,7 @@ QString EntryAttachmentsModel::keyByIndex(const QModelIndex& index) const
|
||||
void EntryAttachmentsModel::attachmentChange(const QString& key)
|
||||
{
|
||||
int row = m_entryAttachments->keys().indexOf(key);
|
||||
Q_EMIT dataChanged(index(row, 0), index(row, columnCount()-1));
|
||||
emit dataChanged(index(row, 0), index(row, columnCount()-1));
|
||||
}
|
||||
|
||||
void EntryAttachmentsModel::attachmentAboutToAdd(const QString& key)
|
||||
|
@ -34,7 +34,7 @@ public:
|
||||
QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override;
|
||||
QString keyByIndex(const QModelIndex& index) const;
|
||||
|
||||
private Q_SLOTS:
|
||||
private slots:
|
||||
void attachmentChange(const QString& key);
|
||||
void attachmentAboutToAdd(const QString& key);
|
||||
void attachmentAdd();
|
||||
|
@ -147,7 +147,7 @@ void EntryAttributesModel::attributeChange(const QString& key)
|
||||
{
|
||||
int row = m_attributes.indexOf(key);
|
||||
Q_ASSERT(row != -1);
|
||||
Q_EMIT dataChanged(index(row, 0), index(row, columnCount()-1));
|
||||
emit dataChanged(index(row, 0), index(row, columnCount()-1));
|
||||
}
|
||||
|
||||
void EntryAttributesModel::attributeAboutToAdd(const QString& key)
|
||||
@ -213,7 +213,7 @@ void EntryAttributesModel::attributeRename(const QString& oldKey, const QString&
|
||||
m_nextRenameDataChange = false;
|
||||
|
||||
QModelIndex keyIndex = index(m_attributes.indexOf(newKey), 0);
|
||||
Q_EMIT dataChanged(keyIndex, keyIndex);
|
||||
emit dataChanged(keyIndex, keyIndex);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -38,7 +38,7 @@ public:
|
||||
QModelIndex indexByKey(const QString& key) const;
|
||||
QString keyByIndex(const QModelIndex& index) const;
|
||||
|
||||
private Q_SLOTS:
|
||||
private slots:
|
||||
void attributeChange(const QString& key);
|
||||
void attributeAboutToAdd(const QString& key);
|
||||
void attributeAdd();
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user