Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
[submodule "src/safariwebextension/keepassxc-browser"]
path = src/safariwebextension/keepassxc-browser
url = https://github.com/sebastianlivoni/keepassxc-browser.git
branch = feature/safari
12 changes: 11 additions & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,9 @@ option(WITH_XC_UPDATECHECK "Include automatic update checks; disable for control
if(UNIX AND NOT APPLE)
option(WITH_XC_FDOSECRETS "Implement freedesktop.org Secret Storage Spec server side API." OFF)
endif()
if (APPLE)
option(WITH_XC_SAFARI_WEB_EXTENSION "Include Safari Web Extension for browser intergration with keepassxc-browser")
endif()
option(WITH_XC_DOCS "Enable building of documentation" ON)

set(WITH_XC_X11 ON CACHE BOOL "Enable building with X11 deps")
Expand Down Expand Up @@ -106,6 +109,9 @@ if(WITH_XC_ALL)
if(UNIX AND NOT APPLE)
set(WITH_XC_FDOSECRETS ON)
endif()
if(APPLE)
set(WITH_XC_SAFARI_WEB_EXTENSION ON)
endif()
endif()

# Prefer WITH_XC_NETWORKING setting over WITH_XC_UPDATECHECK
Expand All @@ -119,6 +125,10 @@ if(UNIX AND NOT APPLE AND NOT WITH_XC_X11)
set(WITH_XC_AUTOTYPE OFF)
endif()

if(APPLE AND WITH_XC_SAFARI_WEB_EXTENSION AND NOT WITH_XC_BROWSER)
message(FATAL_ERROR "Safari Web Extension requires keepassxc-browser browser integration (set it with WITH_XC_BROWSER)")
endif()

set(KEEPASSXC_VERSION_MAJOR "2")
set(KEEPASSXC_VERSION_MINOR "8")
set(KEEPASSXC_VERSION_PATCH "0")
Expand Down Expand Up @@ -211,7 +221,7 @@ if(BOTAN_VERSION VERSION_GREATER_EQUAL "3.0.0")
set(WITH_XC_BOTAN3 TRUE)
elseif(BOTAN_VERSION VERSION_LESS "2.11.0")
# Check for minimum Botan version
message(FATAL_ERROR "Botan 2.11.0 or higher is required")
message(FATAL_ERROR "Botan 2.11.0 or higher is required")
endif()
include_directories(SYSTEM ${BOTAN_INCLUDE_DIR})

Expand Down
1 change: 1 addition & 0 deletions INSTALL.md
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@ KeePassXC comes with a variety of build options that can turn on/off features. M
-DWITH_XC_YUBIKEY=[ON|OFF] Enable/Disable YubiKey HMAC-SHA1 authentication support (default: OFF)
-DWITH_XC_BROWSER=[ON|OFF] Enable/Disable KeePassXC-Browser extension support (default: OFF)
-DWITH_XC_BROWSER_PASSKEYS=[ON|OFF] Enable/Disable Passkeys support for browser integration (default: OFF)
-DWITH_XC_SAFARI_WEB_EXTENSION=[ON|OFF] Enable/Disable Safari Web Extension for browser integration (default: OFF)
-DWITH_XC_NETWORKING=[ON|OFF] Enable/Disable Networking support (e.g., favicon downloading) (default: OFF)
-DWITH_XC_SSHAGENT=[ON|OFF] Enable/Disable SSHAgent support (default: OFF)
-DWITH_XC_FDOSECRETS=[ON|OFF] (Linux Only) Enable/Disable Freedesktop.org Secrets Service support (default:OFF)
Expand Down
3 changes: 2 additions & 1 deletion cmake/CLangFormat.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,8 @@ set(EXCLUDED_FILES
src/gui/tag/TagsEdit.\\*
tests/modeltest.\\*
# objective-c files
src/core/ScreenLockListenerMac.\\*)
src/core/ScreenLockListenerMac.\\*
src/safariwebextension/SafariWebExtensionHandler.\\*)

set(FIND_EXCLUDE_DIR_EXPR "")
foreach(EXCLUDE ${EXCLUDED_DIRS})
Expand Down
15 changes: 14 additions & 1 deletion release-tool
Original file line number Diff line number Diff line change
Expand Up @@ -1211,9 +1211,22 @@ appsign() {
cd "${orig_dir}"
exitError "Signing failed!"
fi

# Sign safariwebextension extension
local safari_web_extension_dir="${app_dir_tmp}/Contents/PlugIns/KeePassXCSafariWebExtension.appex/Contents/MacOS/KeePassXCSafariWebExtension"
if [ -f "${safari_web_extension_dir}" ]; then
if ! xcrun codesign --sign "${key}" --verbose --force --options runtime --entitlements \
"${real_src_dir}/build/share/macosx/safariwebextension.entitlements" "${safari_web_extension_dir}"; then
cd "${orig_dir}"
exitError "Signing failed!"
fi
else
echo "Skipping signing Safari Web Extension as it does not exists."
fi

# Sign main executable with additional entitlements
if ! xcrun codesign --sign "${key}" --verbose --force --options runtime --entitlements \
"${real_src_dir}/share/macosx/keepassxc.entitlements" "${app_dir_tmp}/Contents/MacOS/KeePassXC"; then
"${real_src_dir}/build/share/macosx/keepassxc.entitlements" "${app_dir_tmp}/Contents/MacOS/KeePassXC"; then
cd "${orig_dir}"
exitError "Signing failed!"
fi
Expand Down
2 changes: 1 addition & 1 deletion share/macosx/Info.plist.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
<key>CFBundleIconFile</key>
<string>keepassxc.icns</string>
<key>CFBundleIdentifier</key>
<string>org.keepassxc.keepassxc</string>
<string>${APPLE_APP_IDENTIFIER}</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
Expand Down
9 changes: 7 additions & 2 deletions share/macosx/keepassxc.entitlements
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,15 @@
<plist version="1.0">
<dict>
<key>com.apple.application-identifier</key>
<string>G2S7P7J672.org.keepassxc.keepassxc</string>
<string>${APPLE_TEAM_ID}.${APPLE_APP_IDENTIFIER}</string>
<key>com.apple.security.application-groups</key>
<array>
<string>${APPLE_TEAM_ID}.${APPLE_APP_IDENTIFIER}</string>
</array>
<key>keychain-access-groups</key>
<array>
<string>G2S7P7J672.org.keepassxc.keepassxc</string>
<string>${APPLE_TEAM_ID}.${APPLE_APP_IDENTIFIER}</string>
</array>
@EXTRA_ENTITLEMENTS@
</dict>
</plist>
27 changes: 23 additions & 4 deletions src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ add_feature_info(Auto-Type WITH_XC_AUTOTYPE "Automatic password typing")
add_feature_info(Networking WITH_XC_NETWORKING "Compile KeePassXC with network access code (e.g. for downloading website icons)")
add_feature_info(KeePassXC-Browser WITH_XC_BROWSER "Browser integration with KeePassXC-Browser")
add_feature_info(Passkeys WITH_XC_BROWSER_PASSKEYS "Passkeys support for browser integration")
add_feature_info(SafariWebExtension WITH_XC_SAFARI_WEB_EXTENSION "Safari Web Extension for browser integration")
add_feature_info(SSHAgent WITH_XC_SSHAGENT "SSH agent integration compatible with KeeAgent")
add_feature_info(KeeShare WITH_XC_KEESHARE "Sharing integration with KeeShare")
add_feature_info(YubiKey WITH_XC_YUBIKEY "YubiKey HMAC-SHA1 challenge-response")
Expand Down Expand Up @@ -262,7 +263,7 @@ if(UNIX AND NOT APPLE)

find_library(KEYUTILS_LIBRARIES NAMES keyutils)
if(NOT KEYUTILS_LIBRARIES)
message(FATAL_ERROR "Could not find libkeyutils")
message(FATAL_ERROR "Could not find libkeyutils")
endif()
endif()

Expand Down Expand Up @@ -307,6 +308,10 @@ if(WITH_XC_BROWSER_PASSKEYS)
gui/passkeys/PasskeyImportDialog.cpp)
endif()

if(WITH_XC_SAFARI_WEB_EXTENSION)
add_subdirectory(safariwebextension)
endif()

add_subdirectory(autotype)
add_subdirectory(cli)
add_subdirectory(qrcode)
Expand Down Expand Up @@ -370,7 +375,7 @@ configure_file(git-info.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/git-info.h)
# Core Library Definition
add_library(keepassxc_core STATIC ${core_SOURCES})
set_target_properties(keepassxc_core PROPERTIES COMPILE_DEFINITIONS KEEPASSX_BUILDING_CORE)
target_link_libraries(keepassxc_core
target_link_libraries(keepassxc_core
${qrcode_LIB}
Qt5::Core
Qt5::Concurrent
Expand All @@ -397,7 +402,10 @@ target_link_libraries(keepassxc_gui
${sshagent_LIB})

if(APPLE)
target_link_libraries(keepassxc_gui "-framework Foundation -framework AppKit -framework Carbon -framework Security -framework LocalAuthentication -framework ScreenCaptureKit")
target_compile_definitions(keepassxc_core PRIVATE
APP_GROUP_IDENTIFIER="${APPLE_TEAM_ID}.${APPLE_APP_IDENTIFIER}")

target_link_libraries(keepassxc_gui "-framework Foundation -framework AppKit -framework Carbon -framework Security -framework LocalAuthentication -framework ScreenCaptureKit -framework SafariServices")
if(Qt5MacExtras_FOUND)
target_link_libraries(keepassxc_gui Qt5::MacExtras)
endif()
Expand Down Expand Up @@ -439,12 +447,23 @@ set_target_properties(${PROGNAME} PROPERTIES ENABLE_EXPORTS ON)

# macOS App Bundle
if(APPLE AND WITH_APP_BUNDLE)
set(APPLE_TEAM_ID "G2S7P7J672" CACHE STRING "Apple Developer Team ID")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We need to check this ID.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

its came from share/macosx/keepassxc.entitlements

set(APPLE_APP_IDENTIFIER "org.keepassxc.keepassxc" CACHE STRING "App bundle identifier")

install(FILES ${CMAKE_SOURCE_DIR}/share/macosx/embedded.provisionprofile DESTINATION ${BUNDLE_INSTALL_DIR})
configure_file(${CMAKE_SOURCE_DIR}/share/macosx/Info.plist.cmake ${CMAKE_CURRENT_BINARY_DIR}/Info.plist)

if(CMAKE_BUILD_TYPE_LOWER STREQUAL "debug")
set(EXTRA_ENTITLEMENTS "<key>com.apple.security.cs.disable-library-validation</key>\n\t<true/>\n\t<key>com.apple.security.get-task-allow</key>\n\t<true/>")
else()
set(EXTRA_ENTITLEMENTS "")
endif()

configure_file(${CMAKE_SOURCE_DIR}/share/macosx/keepassxc.entitlements ${CMAKE_BINARY_DIR}/share/macosx/keepassxc.entitlements)
set_target_properties(${PROGNAME} PROPERTIES
MACOSX_BUNDLE ON
MACOSX_BUNDLE_INFO_PLIST ${CMAKE_CURRENT_BINARY_DIR}/Info.plist
CPACK_BUNDLE_APPLE_ENTITLEMENTS "${CMAKE_SOURCE_DIR}/share/macosx/keepassxc.entitlements")
CPACK_BUNDLE_APPLE_ENTITLEMENTS "${CMAKE_BINARY_DIR}/share/macosx/keepassxc.entitlements")

if(QT_MAC_USE_COCOA AND EXISTS "${QT_LIBRARY_DIR}/Resources/qt_menu.nib")
install(DIRECTORY "${QT_LIBRARY_DIR}/Resources/qt_menu.nib"
Expand Down
30 changes: 30 additions & 0 deletions src/browser/BrowserHost.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,10 @@
#include <QLocalServer>
#include <QLocalSocket>

#ifdef WITH_XC_SAFARI_WEB_EXTENSION
#include "safariwebextension/SafariWebExtensionHelper.h"
#endif

#ifdef Q_OS_WIN
#include <fcntl.h>
#undef NOMINMAX
Expand Down Expand Up @@ -62,6 +66,10 @@ void BrowserHost::proxyConnected()
auto socket = m_localServer->nextPendingConnection();
if (socket) {
m_socketList.append(socket);
#ifdef WITH_XC_SAFARI_WEB_EXTENSION
bool isSafariSocket = safariWebExtensionHelper()->isSafariWebExtension(socket);
m_safariWebExtensionCache.insert(socket, isSafariSocket);
#endif
connect(socket, SIGNAL(readyRead()), this, SLOT(readProxyMessage()));
connect(socket, SIGNAL(disconnected()), this, SLOT(proxyDisconnected()));
}
Expand Down Expand Up @@ -94,9 +102,28 @@ void BrowserHost::readProxyMessage()
void BrowserHost::broadcastClientMessage(const QJsonObject& json)
{
QString reply(QJsonDocument(json).toJson(QJsonDocument::Compact));

#ifdef WITH_XC_SAFARI_WEB_EXTENSION
bool containsSafariWebExtensionSocket = false;
#endif

// Send message to all non-Safari sockets
for (const auto socket : m_socketList) {
#ifdef WITH_XC_SAFARI_WEB_EXTENSION
if (m_safariWebExtensionCache.contains(socket)) {
containsSafariWebExtensionSocket = true;
continue; // Skip Safari web extension sockets because we are using SFSafariApplication instead
}
#endif

sendClientData(socket, reply);
}

#ifdef WITH_XC_SAFARI_WEB_EXTENSION
if (containsSafariWebExtensionSocket) {
safariWebExtensionHelper()->broadcastClientMessage(reply);
}
#endif
}

void BrowserHost::sendClientMessage(QLocalSocket* socket, const QJsonObject& json)
Expand All @@ -118,4 +145,7 @@ void BrowserHost::proxyDisconnected()
{
auto socket = qobject_cast<QLocalSocket*>(QObject::sender());
m_socketList.removeOne(socket);
#ifdef WITH_XC_SAFARI_WEB_EXTENSION
m_safariWebExtensionCache.remove(socket);
#endif
}
6 changes: 6 additions & 0 deletions src/browser/BrowserHost.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@
#include <QJsonObject>
#include <QObject>
#include <QPointer>
#ifdef WITH_XC_SAFARI_WEB_EXTENSION
#include <QHash>
#endif

class QLocalServer;
class QLocalSocket;
Expand Down Expand Up @@ -54,6 +57,9 @@ private slots:
private:
QPointer<QLocalServer> m_localServer;
QList<QLocalSocket*> m_socketList;
#ifdef WITH_XC_SAFARI_WEB_EXTENSION
QHash<QLocalSocket*, bool> m_safariWebExtensionCache;
#endif
};

#endif // KEEPASSXC_NATIVEMESSAGINGHOST_H
12 changes: 12 additions & 0 deletions src/browser/BrowserSettingsWidget.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,10 @@
#include "config-keepassx.h"
#include "gui/styles/StateColorPalette.h"

#ifdef WITH_XC_SAFARI_WEB_EXTENSION
#include "safariwebextension/SafariWebExtensionCheckbox.h"
#endif

#include <QFileDialog>

BrowserSettingsWidget::BrowserSettingsWidget(QWidget* parent)
Expand All @@ -44,6 +48,14 @@ BrowserSettingsWidget::BrowserSettingsWidget(QWidget* parent)
connect(m_ui->enableBrowserSupport, SIGNAL(toggled(bool)), m_ui->tabWidget, SLOT(setEnabled(bool)));
connect(m_ui->enableBrowserSupport, SIGNAL(toggled(bool)), SLOT(validateProxyLocation()));

#ifdef WITH_XC_SAFARI_WEB_EXTENSION
SafariWebExtensionCheckbox* safariCheckbox = new SafariWebExtensionCheckbox();
safariCheckbox->setText("Safari");
safariCheckbox->setChecked(false);

m_ui->gridLayout->addWidget(safariCheckbox, 1, 3);
#endif

// Custom Browser option
#ifdef Q_OS_WIN
// TODO: Custom browser is disabled on Windows
Expand Down
8 changes: 7 additions & 1 deletion src/browser/BrowserShared.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,10 @@
#include <QProcessEnvironment>
#endif

#if defined(Q_OS_MACOS)
#include "BrowserSharedMac.h"
#endif

namespace BrowserShared
{
QString localServerPath()
Expand Down Expand Up @@ -53,7 +57,9 @@ namespace BrowserShared
#elif defined(Q_OS_WIN)
// Windows uses named pipes
return serverName + "_" + qgetenv("USERNAME");
#else // Q_OS_MACOS and others
#elif defined(Q_OS_MACOS)
return macOSLocalServerPath();
#else // others
return QStandardPaths::writableLocation(QStandardPaths::TempLocation) + serverName;
#endif
}
Expand Down
6 changes: 6 additions & 0 deletions src/browser/BrowserSharedMac.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#include <QString>

namespace BrowserShared
{
QString macOSLocalServerPath();
}
25 changes: 25 additions & 0 deletions src/browser/BrowserSharedMac.mm
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
#include <Foundation/Foundation.h>
#include <QDir>
#include <QString>

namespace BrowserShared
{
QString macOSLocalServerPath()
{
NSString *appGroupIdentifier = QString::fromUtf8(APP_GROUP_IDENTIFIER).toNSString();

// Get the container URL for the app group identifier
NSURL *containerURL = [[NSFileManager defaultManager] containerURLForSecurityApplicationGroupIdentifier:appGroupIdentifier];

NSString *containerPath = [containerURL path];

QString homePath = QString::fromNSString(containerPath);

QDir().mkpath(homePath);

// The path will become too long therefore we must cut off serverName
QString socketPath = homePath + "/KeePassXC.BrowserServer";

return socketPath;
}
}
23 changes: 22 additions & 1 deletion src/browser/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.

if(WITH_XC_BROWSER)
include_directories(${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR})
include_directories(${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_SOURCE_DIR}/src/safariwebextension)

set(browser_SOURCES
BrowserAccessControlDialog.cpp
Expand All @@ -31,6 +31,17 @@ if(WITH_XC_BROWSER)
CustomTableWidget.cpp
NativeMessageInstaller.cpp)

if(APPLE)
list(APPEND browser_SOURCES
BrowserSharedMac.mm)

if(WITH_XC_SAFARI_WEB_EXTENSION)
list(APPEND browser_SOURCES
../safariwebextension/SafariWebExtensionHelper.mm
../safariwebextension/SafariWebExtensionCheckbox.mm)
endif()
endif()

if(WITH_XC_BROWSER_PASSKEYS)
list(APPEND browser_SOURCES
BrowserCbor.cpp
Expand All @@ -41,5 +52,15 @@ if(WITH_XC_BROWSER)
endif()

add_library(browser STATIC ${browser_SOURCES})

if(APPLE)
target_compile_definitions(browser PRIVATE
APP_GROUP_IDENTIFIER="${APPLE_TEAM_ID}.${APPLE_APP_IDENTIFIER}" APPLE_APP_IDENTIFIER="${APPLE_APP_IDENTIFIER}")
endif()

if(WITH_XC_SAFARI_WEB_EXTENSION)
target_compile_definitions(browser PRIVATE WITH_XC_SAFARI_WEB_EXTENSION)
endif()

target_link_libraries(browser Qt5::Core Qt5::Concurrent Qt5::Widgets Qt5::Network ${BOTAN_LIBRARIES})
endif()
Loading