diff options
Diffstat (limited to 'Swift')
-rw-r--r-- | Swift/QtUI/CAPICertificateSelector.cpp | 138 | ||||
-rw-r--r-- | Swift/QtUI/CAPICertificateSelector.h | 13 | ||||
-rw-r--r-- | Swift/QtUI/QtLoginWindow.cpp | 19 | ||||
-rw-r--r-- | Swift/QtUI/SConscript | 3 |
4 files changed, 169 insertions, 4 deletions
diff --git a/Swift/QtUI/CAPICertificateSelector.cpp b/Swift/QtUI/CAPICertificateSelector.cpp new file mode 100644 index 0000000..44f5793 --- /dev/null +++ b/Swift/QtUI/CAPICertificateSelector.cpp @@ -0,0 +1,138 @@ +/* + * Copyright (c) 2012 Isode Limited, London, England. + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#include <string> + +#define SECURITY_WIN32 +#include <Windows.h> +#include <WinCrypt.h> +#include <cryptuiapi.h> + +#include "CAPICertificateSelector.h" + +namespace Swift { + +#define cert_dlg_title L"TLS Client Certificate Selection" +#define cert_dlg_prompt L"Select a certificate to use for authentication" +/////Hmm, maybe we should not exlude the "location" column +#define exclude_columns CRYPTUI_SELECT_LOCATION_COLUMN \ + |CRYPTUI_SELECT_INTENDEDUSE_COLUMN + + + +static std::string getCertUri(PCCERT_CONTEXT cert, const char * cert_store_name) { + DWORD required_size; + char * comma; + char * p_in; + char * p_out; + char * subject_name; + std::string ret = std::string("certstore:") + cert_store_name + ":"; + + required_size = CertNameToStrA(cert->dwCertEncodingType, + &cert->pCertInfo->Subject, + /* Discard attribute names: */ + CERT_SIMPLE_NAME_STR | CERT_NAME_STR_REVERSE_FLAG, + NULL, + 0); + + subject_name = static_cast<char *>(malloc(required_size+1)); + + if (!CertNameToStrA(cert->dwCertEncodingType, + &cert->pCertInfo->Subject, + /* Discard attribute names: */ + CERT_SIMPLE_NAME_STR | CERT_NAME_STR_REVERSE_FLAG, + subject_name, + required_size)) { + return ""; + } + + /* Now search for the "," (ignoring escapes) + and truncate the rest of the string */ + if (subject_name[0] == '"') { + for (comma = subject_name + 1; comma[0]; comma++) { + if (comma[0] == '"') { + comma++; + if (comma[0] != '"') { + break; + } + } + } + } else { + comma = strchr(subject_name, ','); + } + + if (comma != NULL) { + *comma = '\0'; + } + + /* We now need to unescape the returned RDN */ + if (subject_name[0] == '"') { + for (p_in = subject_name + 1, p_out = subject_name; p_in[0]; p_in++, p_out++) { + if (p_in[0] == '"') { + p_in++; + } + + p_out[0] = p_in[0]; + } + p_out[0] = '\0'; + } + + ret += subject_name; + free(subject_name); + + return ret; +} + +std::string selectCAPICertificate() { + + const char * cert_store_name = "MY"; + PCCERT_CONTEXT cert; + DWORD store_flags; + HCERTSTORE hstore; + HWND hwnd; + + store_flags = CERT_STORE_OPEN_EXISTING_FLAG | + CERT_STORE_READONLY_FLAG | + CERT_SYSTEM_STORE_CURRENT_USER; + + hstore = CertOpenStore(CERT_STORE_PROV_SYSTEM_A, 0, 0, store_flags, cert_store_name); + if (!hstore) { + return ""; + } + + +////Does this handle need to be freed as well? + hwnd = GetForegroundWindow(); + if (!hwnd) { + hwnd = GetActiveWindow(); + } + + /* Call Windows dialog to select a suitable certificate */ + cert = CryptUIDlgSelectCertificateFromStore(hstore, + hwnd, + cert_dlg_title, + cert_dlg_prompt, + exclude_columns, + 0, + NULL); + + if (hstore) { + CertCloseStore(hstore, 0); + } + + if (cert) { + std::string ret = getCertUri(cert, cert_store_name); + + CertFreeCertificateContext(cert); + + return ret; + } else { + return ""; + } +} + + +} diff --git a/Swift/QtUI/CAPICertificateSelector.h b/Swift/QtUI/CAPICertificateSelector.h new file mode 100644 index 0000000..9a0ee92 --- /dev/null +++ b/Swift/QtUI/CAPICertificateSelector.h @@ -0,0 +1,13 @@ +/* + * Copyright (c) 2012 Isode Limited, London, England. + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#pragma once + +#include <string> + +namespace Swift { + std::string selectCAPICertificate(); +} diff --git a/Swift/QtUI/QtLoginWindow.cpp b/Swift/QtUI/QtLoginWindow.cpp index 1cd3206..6b9d389 100644 --- a/Swift/QtUI/QtLoginWindow.cpp +++ b/Swift/QtUI/QtLoginWindow.cpp @@ -9,70 +9,74 @@ #include <boost/bind.hpp> #include <boost/smart_ptr/make_shared.hpp> #include <algorithm> #include <cassert> #include <QApplication> #include <QBoxLayout> #include <QComboBox> #include <QDesktopWidget> #include <QFileDialog> #include <QStatusBar> #include <QToolButton> #include <QLabel> #include <QMenuBar> #include <QHBoxLayout> #include <qdebug.h> #include <QCloseEvent> #include <QCursor> #include <QMessageBox> #include <QKeyEvent> #include <Swift/Controllers/UIEvents/UIEventStream.h> #include <Swift/Controllers/UIEvents/RequestXMLConsoleUIEvent.h> #include <Swift/Controllers/UIEvents/RequestFileTransferListUIEvent.h> #include <Swift/Controllers/Settings/SettingsProvider.h> #include <Swift/Controllers/SettingConstants.h> #include <Swift/QtUI/QtUISettingConstants.h> #include <Swiften/Base/Platform.h> #include <Swiften/Base/Paths.h> #include <QtAboutWidget.h> #include <QtSwiftUtil.h> #include <QtMainWindow.h> #include <QtUtilities.h> +#ifdef HAVE_SCHANNEL +#include "CAPICertificateSelector.h" +#endif + namespace Swift{ QtLoginWindow::QtLoginWindow(UIEventStream* uiEventStream, SettingsProvider* settings) : QMainWindow(), settings_(settings) { uiEventStream_ = uiEventStream; setWindowTitle("Swift"); #ifndef Q_WS_MAC setWindowIcon(QIcon(":/logo-icon-16.png")); #endif QtUtilities::setX11Resource(this, "Main"); resize(200, 500); setContentsMargins(0,0,0,0); QWidget *centralWidget = new QWidget(this); setCentralWidget(centralWidget); QBoxLayout *topLayout = new QBoxLayout(QBoxLayout::TopToBottom, centralWidget); stack_ = new QStackedWidget(centralWidget); topLayout->addWidget(stack_); topLayout->setMargin(0); loginWidgetWrapper_ = new QWidget(this); loginWidgetWrapper_->setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding)); QBoxLayout *layout = new QBoxLayout(QBoxLayout::TopToBottom, loginWidgetWrapper_); layout->addStretch(2); QLabel* logo = new QLabel(this); logo->setPixmap(QPixmap(":/logo-shaded-text.256.png")); logo->setScaledContents(true); logo->setFixedSize(192,192); QWidget *logoWidget = new QWidget(this); QHBoxLayout *logoLayout = new QHBoxLayout(); logoLayout->setMargin(0); logoLayout->addStretch(0); logoLayout->addWidget(logo); logoLayout->addStretch(0); @@ -325,74 +329,81 @@ void QtLoginWindow::setIsLoggingIn(bool loggingIn) { bool eagle = settings_->getSetting(SettingConstants::FORGET_PASSWORDS); remember_->setEnabled(!eagle); loginAutomatically_->setEnabled(!eagle); } void QtLoginWindow::loginClicked() { if (username_->isEnabled()) { std::string banner = settings_->getSetting(QtUISettingConstants::CLICKTHROUGH_BANNER); if (!banner.empty()) { QMessageBox msgBox; msgBox.setWindowTitle(tr("Confirm terms of use")); msgBox.setText(""); msgBox.setInformativeText(P2QSTRING(banner)); msgBox.setStandardButtons(QMessageBox::Yes | QMessageBox::No); msgBox.setDefaultButton(QMessageBox::No); if (msgBox.exec() != QMessageBox::Yes) { return; } } onLoginRequest(Q2PSTRING(username_->currentText()), Q2PSTRING(password_->text()), Q2PSTRING(certificateFile_), remember_->isChecked(), loginAutomatically_->isChecked()); if (settings_->getSetting(SettingConstants::FORGET_PASSWORDS)) { /* Mustn't remember logins */ username_->clearEditText(); password_->setText(""); } } else { onCancelLoginRequest(); } } void QtLoginWindow::setLoginAutomatically(bool loginAutomatically) { loginAutomatically_->setChecked(loginAutomatically); } void QtLoginWindow::handleCertficateChecked(bool checked) { if (checked) { - certificateFile_ = QFileDialog::getOpenFileName(this, tr("Select an authentication certificate"), QString(), QString("*.cert;*.p12;*.pfx")); - if (certificateFile_.isEmpty()) { - certificateButton_->setChecked(false); - } +#ifdef HAVE_SCHANNEL + certificateFile_ = selectCAPICertificate(); + if (certificateFile_.isEmpty()) { + certificateButton_->setChecked(false); + } +#else + certificateFile_ = QFileDialog::getOpenFileName(this, tr("Select an authentication certificate"), QString(), QString("*.cert;*.p12;*.pfx")); + if (certificateFile_.isEmpty()) { + certificateButton_->setChecked(false); + } +#endif } else { certificateFile_ = ""; } } void QtLoginWindow::handleAbout() { if (!aboutDialog_) { aboutDialog_ = new QtAboutWidget(); aboutDialog_->show(); } else { aboutDialog_->show(); aboutDialog_->raise(); aboutDialog_->activateWindow(); } } void QtLoginWindow::handleShowXMLConsole() { uiEventStream_->send(boost::shared_ptr<RequestXMLConsoleUIEvent>(new RequestXMLConsoleUIEvent())); } void QtLoginWindow::handleShowFileTransferOverview() { uiEventStream_->send(boost::make_shared<RequestFileTransferListUIEvent>()); } void QtLoginWindow::handleToggleSounds(bool enabled) { settings_->storeSetting(SettingConstants::PLAY_SOUNDS, enabled); } void QtLoginWindow::handleToggleNotifications(bool enabled) { settings_->storeSetting(SettingConstants::SHOW_NOTIFICATIONS, enabled); } void QtLoginWindow::handleQuit() { diff --git a/Swift/QtUI/SConscript b/Swift/QtUI/SConscript index d37958f..a8b8c78 100644 --- a/Swift/QtUI/SConscript +++ b/Swift/QtUI/SConscript @@ -23,70 +23,72 @@ myenv = env.Clone() myenv["CXXFLAGS"] = filter(lambda x : x != "-Wfloat-equal", myenv["CXXFLAGS"]) myenv.UseFlags(env["SWIFT_CONTROLLERS_FLAGS"]) myenv.UseFlags(env["SWIFTOOLS_FLAGS"]) if myenv["HAVE_XSS"] : myenv.UseFlags(env["XSS_FLAGS"]) if env["PLATFORM"] == "posix" : myenv.Append(LIBS = ["X11"]) if myenv["HAVE_SPARKLE"] : myenv.UseFlags(env["SPARKLE_FLAGS"]) myenv.UseFlags(env["SWIFTEN_FLAGS"]) myenv.UseFlags(env["SWIFTEN_DEP_FLAGS"]) if myenv.get("HAVE_GROWL", False) : myenv.UseFlags(myenv["GROWL_FLAGS"]) myenv.Append(CPPDEFINES = ["HAVE_GROWL"]) if myenv["swift_mobile"] : myenv.Append(CPPDEFINES = ["SWIFT_MOBILE"]) if myenv.get("HAVE_SNARL", False) : myenv.UseFlags(myenv["SNARL_FLAGS"]) myenv.Append(CPPDEFINES = ["HAVE_SNARL"]) myenv.UseFlags(myenv["PLATFORM_FLAGS"]) myenv.Tool("qt4", toolpath = ["#/BuildTools/SCons/Tools"]) myenv.Tool("nsis", toolpath = ["#/BuildTools/SCons/Tools"]) myenv.Tool("wix", toolpath = ["#/BuildTools/SCons/Tools"]) qt4modules = ['QtCore', 'QtGui', 'QtWebKit'] if env["PLATFORM"] == "posix" : qt4modules += ["QtDBus"] myenv.EnableQt4Modules(qt4modules, debug = False) myenv.Append(CPPPATH = ["."]) if env["PLATFORM"] == "win32" : #myenv["LINKFLAGS"] = ["/SUBSYSTEM:CONSOLE"] myenv.Append(LINKFLAGS = ["/SUBSYSTEM:WINDOWS"]) myenv.Append(LIBS = "qtmain") + if myenv.get("HAVE_SCHANNEL", 0) : + myenv.Append(LIBS = "Cryptui") myenv.WriteVal("DefaultTheme.qrc", myenv.Value(generateDefaultTheme(myenv.Dir("#/Swift/resources/themes/Default")))) sources = [ "main.cpp", "QtAboutWidget.cpp", "QtAvatarWidget.cpp", "QtUIFactory.cpp", "QtChatWindowFactory.cpp", "QtChatWindow.cpp", "QtClickableLabel.cpp", "QtLoginWindow.cpp", "QtMainWindow.cpp", "QtProfileWindow.cpp", "QtNameWidget.cpp", "QtSettingsProvider.cpp", "QtStatusWidget.cpp", "QtScaledAvatarCache.cpp", "QtSwift.cpp", "QtURIHandler.cpp", "QtChatView.cpp", "QtChatTheme.cpp", "QtChatTabs.cpp", "QtSoundPlayer.cpp", "QtSystemTray.cpp", "QtCachedImageScaler.cpp", "QtTabbable.cpp", "QtTabWidget.cpp", "QtTextEdit.cpp", "QtXMLConsoleWidget.cpp", "QtFileTransferListWidget.cpp", "QtFileTransferListItemModel.cpp", "QtAdHocCommandWindow.cpp", "QtUtilities.cpp", "QtBookmarkDetailWindow.cpp", @@ -119,70 +121,71 @@ sources = [ "ChatList/ChatListModel.cpp", "ChatList/ChatListDelegate.cpp", "ChatList/ChatListMUCItem.cpp", "ChatList/ChatListRecentItem.cpp", "MUCSearch/QtMUCSearchWindow.cpp", "MUCSearch/MUCSearchModel.cpp", "MUCSearch/MUCSearchRoomItem.cpp", "MUCSearch/MUCSearchEmptyItem.cpp", "MUCSearch/MUCSearchDelegate.cpp", "UserSearch/QtUserSearchFirstPage.cpp", "UserSearch/QtUserSearchFieldsPage.cpp", "UserSearch/QtUserSearchResultsPage.cpp", "UserSearch/QtUserSearchDetailsPage.cpp", "UserSearch/QtUserSearchWindow.cpp", "UserSearch/UserSearchModel.cpp", "UserSearch/UserSearchDelegate.cpp", "QtSubscriptionRequestWindow.cpp", "QtRosterHeader.cpp", "QtWebView.cpp", "qrc_DefaultTheme.cc", "qrc_Swift.cc", "QtFileTransferJSBridge.cpp", "QtMUCConfigurationWindow.cpp", "QtAffiliationEditor.cpp", "QtUISettingConstants.cpp" ] myenv["SWIFT_VERSION"] = Version.getBuildVersion(env.Dir("#").abspath, "swift") if env["PLATFORM"] == "win32" : res = myenv.RES("#/Swift/resources/Windows/Swift.rc") # For some reason, SCons isn't picking up the dependency correctly # Adding it explicitly until i figure out why myenv.Depends(res, "../Controllers/BuildVersion.h") sources += [ + "CAPICertificateSelector.cpp", "WindowsNotifier.cpp", "#/Swift/resources/Windows/Swift.res" ] if env["PLATFORM"] == "posix" : sources += [ "FreeDesktopNotifier.cpp", "QtDBUSURIHandler.cpp", ] if env["PLATFORM"] == "darwin" or env["PLATFORM"] == "win32" : swiftProgram = myenv.Program("Swift", sources) else : swiftProgram = myenv.Program("swift", sources) if env["PLATFORM"] != "darwin" and env["PLATFORM"] != "win32" : openURIProgram = myenv.Program("swift-open-uri", "swift-open-uri.cpp") else : openURIProgram = [] myenv.Uic4("MUCSearch/QtMUCSearchWindow.ui") myenv.Uic4("UserSearch/QtUserSearchWizard.ui") myenv.Uic4("UserSearch/QtUserSearchFirstPage.ui") myenv.Uic4("UserSearch/QtUserSearchFieldsPage.ui") myenv.Uic4("UserSearch/QtUserSearchResultsPage.ui") myenv.Uic4("QtBookmarkDetailWindow.ui") myenv.Uic4("QtAffiliationEditor.ui") myenv.Uic4("QtJoinMUCWindow.ui") myenv.Qrc("DefaultTheme.qrc") myenv.Qrc("Swift.qrc") # Resources commonResources = { "": ["#/Swift/resources/sounds"] } |