aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorFelix (xq) Queißner <git@mq32.de>2020-06-10 21:38:05 +0200
committerFelix (xq) Queißner <git@mq32.de>2020-06-10 21:38:05 +0200
commitab3e5ad5f25862985c17ba557163a1902b54747f (patch)
treeab91f5b8a245a6b506a00e9b0533b096d0753ea4 /src
parentfeb37f7d6b8730e94821fc6d70fb742ff393517d (diff)
downloadkristall-ab3e5ad5f25862985c17ba557163a1902b54747f.tar.gz
Adds install target to makefile, adds support for transient client certificates.
Diffstat (limited to 'src')
-rw-r--r--src/browsertab.cpp85
-rw-r--r--src/browsertab.hpp12
-rw-r--r--src/browsertab.ui33
-rw-r--r--src/builtins.qrc6
-rw-r--r--src/certificatehelper.cpp79
-rw-r--r--src/certificatehelper.hpp17
-rw-r--r--src/certificateselectiondialog.cpp71
-rw-r--r--src/certificateselectiondialog.hpp46
-rw-r--r--src/certificateselectiondialog.ui154
-rw-r--r--src/cryptoidentity.cpp2
-rw-r--r--src/cryptoidentity.hpp24
-rw-r--r--src/geminiclient.cpp21
-rw-r--r--src/geminiclient.hpp5
-rw-r--r--src/icons.qrc4
-rw-r--r--src/icons/shield-lock.svg1
-rw-r--r--src/icons/shield-outline.svg1
-rw-r--r--src/kristall.pro10
-rw-r--r--src/mainwindow.cpp2
18 files changed, 552 insertions, 21 deletions
diff --git a/src/browsertab.cpp b/src/browsertab.cpp
index d9f2ffa..d566da6 100644
--- a/src/browsertab.cpp
+++ b/src/browsertab.cpp
@@ -7,6 +7,8 @@
#include "geminirenderer.hpp"
#include "plaintextrenderer.hpp"
+#include "certificateselectiondialog.hpp"
+
#include "ioutil.hpp"
#include "kristall.hpp"
@@ -108,7 +110,6 @@ void BrowserTab::navigateTo(const QUrl &url, PushToHistory mode)
this->redirection_count = 0;
this->successfully_loaded = false;
- this->push_to_history_after_load = (mode == PushAfterSuccess);
if(url.scheme() == "gemini")
{
@@ -146,10 +147,6 @@ void BrowserTab::navigateTo(const QUrl &url, PushToHistory mode)
else if(url.scheme() == "about")
{
this->redirection_count = 0;
- this->push_to_history_after_load = false;
-
- if(mode == PushAfterSuccess)
- mode = PushImmediate;
if(url.path() == "blank")
{
this->on_requestComplete("", "text/gemini");
@@ -186,7 +183,6 @@ void BrowserTab::navigateTo(const QUrl &url, PushToHistory mode)
switch(mode)
{
case DontPush:
- case PushAfterSuccess:
break;
case PushImmediate:
@@ -403,11 +399,6 @@ File Size: %2
this->successfully_loaded = true;
- if(this->push_to_history_after_load) {
- this->pushToHistory(this->current_location);
- this->push_to_history_after_load = false;
- }
-
this->updateUI();
}
@@ -494,13 +485,21 @@ void BrowserTab::on_permanentFailure(PermanentFailure reason, const QString &inf
void BrowserTab::on_transientCertificateRequested(const QString &reason)
{
- QMessageBox::warning(this, "Kristall", "Transient certificate requirested:\n" + reason);
+ if(not trySetClientCertificate(reason)) {
+ setErrorMessage(QString("The page requested a transient client certificate, but none was provided.\r\nOriginal query was: %1").arg(reason));
+ } else {
+ this->navigateTo(this->current_location, DontPush);
+ }
this->updateUI();
}
void BrowserTab::on_authorisedCertificateRequested(const QString &reason)
{
- QMessageBox::warning(this, "Kristall", "Authorized certificate requirested:\n" + reason);
+ if(not trySetClientCertificate(reason)) {
+ setErrorMessage(QString("The page requested a authorized client certificate, but none was provided.\r\nOriginal query was: %1").arg(reason));
+ } else {
+ this->navigateTo(this->current_location, DontPush);
+ }
this->updateUI();
}
@@ -530,8 +529,11 @@ void BrowserTab::on_linkHovered(const QString &url)
void BrowserTab::setErrorMessage(const QString &msg)
{
- // this->page.setContent(QString("An error happened:\n%0").arg(msg).toUtf8(), "text/plain charset=utf-8");
- QMessageBox::warning(this, "Kristall", msg);
+ this->on_requestComplete(
+ QString("An error happened:\r\n%0").arg(msg).toUtf8(),
+ "text/plain charset=utf-8"
+ );
+
this->updateUI();
}
@@ -560,7 +562,7 @@ void BrowserTab::on_text_browser_anchorClicked(const QUrl &url)
auto support = mainWindow->protocols.isSchemeSupported(real_url.scheme());
if(support == ProtocolSetup::Enabled) {
- this->navigateTo(real_url, PushAfterSuccess);
+ this->navigateTo(real_url, PushImmediate);
} else {
bool use_os_proxy = global_settings.value("use_os_scheme_handler").toBool();
@@ -624,6 +626,48 @@ void BrowserTab::updateUI()
this->ui->fav_button->setChecked(this->mainWindow->favourites.contains(this->current_location));
}
+bool BrowserTab::trySetClientCertificate(const QString &query)
+{
+ CertificateSelectionDialog dialog { this };
+
+ dialog.setServerQuery(query);
+
+ if(dialog.exec() != QDialog::Accepted) {
+ this->gemini_client.disableClientCertificate();
+ this->ui->enable_client_cert_button->setChecked(false);
+ return false;
+ }
+
+ this->current_identitiy = dialog.identity();
+
+ if(not current_identitiy.isValid()) {
+ QMessageBox::warning(this, "Kristall", "Failed to generate temporary crypto-identitiy");
+ this->gemini_client.disableClientCertificate();
+ this->ui->enable_client_cert_button->setChecked(false);
+ return false;
+ }
+
+ this->gemini_client.enableClientCertificate(this->current_identitiy);
+ this->ui->enable_client_cert_button->setChecked(true);
+
+ return true;
+}
+
+void BrowserTab::resetClientCertificate()
+{
+ if(this->current_identitiy.isValid() and not this->current_identitiy.is_persistent)
+ {
+ auto respo = QMessageBox::question(this, "Kristall", "You currently have a transient session active!\r\nIf you disable the session, you will not be able to restore it. Continue?");
+ if(respo != QMessageBox::Yes) {
+ this->ui->enable_client_cert_button->setChecked(true);
+ return;
+ }
+ }
+
+ this->gemini_client.disableClientCertificate();
+ this->ui->enable_client_cert_button->setChecked(false);
+}
+
#include <QClipboard>
void BrowserTab::on_text_browser_customContextMenuRequested(const QPoint &pos)
@@ -657,3 +701,12 @@ void BrowserTab::on_text_browser_customContextMenuRequested(const QPoint &pos)
menu.exec(ui->text_browser->mapToGlobal(pos));
}
+
+void BrowserTab::on_enable_client_cert_button_clicked(bool checked)
+{
+ if(checked) {
+ trySetClientCertificate(QString{ });
+ } else {
+ resetClientCertificate();
+ }
+}
diff --git a/src/browsertab.hpp b/src/browsertab.hpp
index 644da70..04e6c0d 100644
--- a/src/browsertab.hpp
+++ b/src/browsertab.hpp
@@ -18,6 +18,8 @@
#include "gopherclient.hpp"
#include "fingerclient.hpp"
+#include "cryptoidentity.hpp"
+
namespace Ui {
class BrowserTab;
}
@@ -31,7 +33,6 @@ public:
enum PushToHistory {
DontPush,
PushImmediate,
- PushAfterSuccess,
};
public:
@@ -104,12 +105,18 @@ private slots:
void on_text_browser_customContextMenuRequested(const QPoint &pos);
+ void on_enable_client_cert_button_clicked(bool checked);
+
private:
void setErrorMessage(QString const & msg);
void pushToHistory(QUrl const & url);
void updateUI();
+
+ bool trySetClientCertificate(QString const & query);
+
+ void resetClientCertificate();
public:
Ui::BrowserTab *ui;
@@ -122,7 +129,6 @@ public:
FingerClient finger_client;
int redirection_count = 0;
- bool push_to_history_after_load = false;
bool successfully_loaded = false;
DocumentOutlineModel outline;
@@ -135,6 +141,8 @@ public:
QByteArray current_buffer;
QString current_mime;
QElapsedTimer timer;
+
+ CryptoIdentity current_identitiy;
};
#endif // BROWSERTAB_HPP
diff --git a/src/browsertab.ui b/src/browsertab.ui
index 7be4d3c..46ff31f 100644
--- a/src/browsertab.ui
+++ b/src/browsertab.ui
@@ -51,6 +51,9 @@
<property name="enabled">
<bool>false</bool>
</property>
+ <property name="toolTip">
+ <string>Navigate back</string>
+ </property>
<property name="text">
<string/>
</property>
@@ -65,6 +68,9 @@
<property name="enabled">
<bool>false</bool>
</property>
+ <property name="toolTip">
+ <string>Navigate forward</string>
+ </property>
<property name="text">
<string>...</string>
</property>
@@ -79,6 +85,9 @@
<property name="enabled">
<bool>true</bool>
</property>
+ <property name="toolTip">
+ <string>Stop loading</string>
+ </property>
<property name="text">
<string/>
</property>
@@ -93,6 +102,9 @@
<property name="enabled">
<bool>true</bool>
</property>
+ <property name="toolTip">
+ <string>Refresh current location</string>
+ </property>
<property name="text">
<string/>
</property>
@@ -114,6 +126,9 @@
<property name="enabled">
<bool>false</bool>
</property>
+ <property name="toolTip">
+ <string>Add/remove from favourites</string>
+ </property>
<property name="text">
<string/>
</property>
@@ -130,6 +145,24 @@
</property>
</widget>
</item>
+ <item>
+ <widget class="QToolButton" name="enable_client_cert_button">
+ <property name="toolTip">
+ <string>Enable/disable client certificate for this tab</string>
+ </property>
+ <property name="text">
+ <string>...</string>
+ </property>
+ <property name="icon">
+ <iconset resource="icons.qrc">
+ <normaloff>:/icons/shield-outline.svg</normaloff>
+ <normalon>:/icons/shield-lock.svg</normalon>:/icons/shield-outline.svg</iconset>
+ </property>
+ <property name="checkable">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
</layout>
</item>
<item>
diff --git a/src/builtins.qrc b/src/builtins.qrc
new file mode 100644
index 0000000..fae4cc3
--- /dev/null
+++ b/src/builtins.qrc
@@ -0,0 +1,6 @@
+<RCC>
+ <qresource prefix="/">
+ <file>about/easter-egg.gemini</file>
+ <file>about/help.gemini</file>
+ </qresource>
+</RCC>
diff --git a/src/certificatehelper.cpp b/src/certificatehelper.cpp
new file mode 100644
index 0000000..2b6acb8
--- /dev/null
+++ b/src/certificatehelper.cpp
@@ -0,0 +1,79 @@
+#include "certificatehelper.hpp"
+
+#include <openssl/rsa.h>
+#include <openssl/x509.h>
+#include <openssl/pem.h>
+
+CryptoIdentity CertificateHelper::createNewIdentity(const QString &common_name, QDateTime expiry_date)
+{
+ CryptoIdentity identity;
+
+ auto const now = QDateTime::currentDateTime();
+ if(expiry_date < now)
+ return identity;
+
+ identity.display_name = common_name;
+
+ QByteArray common_name_utf8 = common_name.toUtf8();
+
+ EVP_PKEY * pkey = EVP_PKEY_new();
+ q_check_ptr(pkey);
+ RSA * rsa = RSA_generate_key(2048, RSA_F4, nullptr, nullptr);
+ q_check_ptr(rsa);
+ EVP_PKEY_assign_RSA(pkey, rsa);
+ X509 * x509 = X509_new();
+ q_check_ptr(x509);
+ ASN1_INTEGER_set(X509_get_serialNumber(x509), 1);
+ X509_gmtime_adj(X509_get_notBefore(x509), 0); // not before current time
+ X509_gmtime_adj(X509_get_notAfter(x509), now.secsTo(expiry_date)); // not after a year from this point
+ X509_set_pubkey(x509, pkey);
+ X509_NAME * name = X509_get_subject_name(x509);
+ q_check_ptr(name);
+ // X509_NAME_add_entry_by_txt(name, "C", MBSTRING_ASC, (unsigned char *)"US", -1, -1, 0);
+ // X509_NAME_add_entry_by_txt(name, "O", MBSTRING_ASC, (unsigned char *)"My Organization", -1, -1, 0);
+ X509_NAME_add_entry_by_txt(name, "CN", MBSTRING_ASC, reinterpret_cast<unsigned char const *>(common_name_utf8.data()), common_name_utf8.size(), -1, 0);
+ X509_set_issuer_name(x509, name);
+ X509_sign(x509, pkey, EVP_sha1());
+ BIO * bp_private = BIO_new(BIO_s_mem());
+ q_check_ptr(bp_private);
+ if(PEM_write_bio_PrivateKey(bp_private, pkey, nullptr, nullptr, 0, nullptr, nullptr) != 1)
+ {
+ EVP_PKEY_free(pkey);
+ X509_free(x509);
+ BIO_free_all(bp_private);
+ qFatal("PEM_write_bio_PrivateKey");
+ }
+ BIO * bp_public = BIO_new(BIO_s_mem());
+ q_check_ptr(bp_public);
+ if(PEM_write_bio_X509(bp_public, x509) != 1)
+ {
+ EVP_PKEY_free(pkey);
+ X509_free(x509);
+ BIO_free_all(bp_public);
+ BIO_free_all(bp_private);
+ qFatal("PEM_write_bio_PrivateKey");
+ }
+
+ const char * buffer = nullptr;
+ size_t size = BIO_get_mem_data(bp_public, &buffer);
+ q_check_ptr(buffer);
+ identity.certificate = QSslCertificate(QByteArray(buffer, size));
+ if(identity.certificate.isNull())
+ {
+ qFatal("Failed to generate a random client certificate");
+ }
+ size = BIO_get_mem_data(bp_private, &buffer);
+ q_check_ptr(buffer);
+ identity.private_key = QSslKey(QByteArray(buffer, size), QSsl::Rsa);
+ if(identity.private_key.isNull())
+ {
+ qFatal("Failed to generate a random private key");
+ }
+
+ EVP_PKEY_free(pkey); // this will also free the rsa key
+ X509_free(x509);
+ BIO_free_all(bp_public);
+ BIO_free_all(bp_private);
+
+ return identity;
+}
diff --git a/src/certificatehelper.hpp b/src/certificatehelper.hpp
new file mode 100644
index 0000000..e395666
--- /dev/null
+++ b/src/certificatehelper.hpp
@@ -0,0 +1,17 @@
+#ifndef CERTIFICATEHELPER_HPP
+#define CERTIFICATEHELPER_HPP
+
+#include "cryptoidentity.hpp"
+
+struct CertificateHelper
+{
+ CertificateHelper() = delete;
+
+
+
+ static CryptoIdentity createNewIdentity(
+ QString const & common_name,
+ QDateTime expiry_date);
+};
+
+#endif // CERTIFICATEHELPER_HPP
diff --git a/src/certificateselectiondialog.cpp b/src/certificateselectiondialog.cpp
new file mode 100644
index 0000000..70dac42
--- /dev/null
+++ b/src/certificateselectiondialog.cpp
@@ -0,0 +1,71 @@
+#include "certificateselectiondialog.hpp"
+#include "ui_certificateselectiondialog.h"
+
+#include "certificatehelper.hpp"
+
+CertificateSelectionDialog::CertificateSelectionDialog(QWidget *parent) :
+ QDialog(parent),
+ ui(new Ui::CertificateSelectionDialog)
+{
+ ui->setupUi(this);
+ this->ui->server_request->setVisible(false);
+}
+
+CertificateSelectionDialog::~CertificateSelectionDialog()
+{
+ delete ui;
+}
+
+void CertificateSelectionDialog::setServerQuery(const QString &query)
+{
+ this->ui->server_request->setText(query);
+ this->ui->server_request->setVisible(not query.isEmpty());
+}
+
+CryptoIdentity CertificateSelectionDialog::identity() const
+{
+ return cryto_identity;
+}
+
+void CertificateSelectionDialog::on_use_temp_cert_30m_clicked()
+{
+ acceptTemporaryWithTimeout(QDateTime::currentDateTime().addSecs(1800 * 12));
+}
+
+void CertificateSelectionDialog::on_use_temp_cert_1h_clicked()
+{
+ acceptTemporaryWithTimeout(QDateTime::currentDateTime().addSecs(3600));
+}
+
+void CertificateSelectionDialog::on_use_temp_cert_12h_clicked()
+{
+ acceptTemporaryWithTimeout(QDateTime::currentDateTime().addSecs(3600 * 12));
+}
+
+void CertificateSelectionDialog::on_use_temp_cert_24h_clicked()
+{
+ acceptTemporaryWithTimeout(QDateTime::currentDateTime().addDays(1));
+}
+
+void CertificateSelectionDialog::on_use_temp_cert_48h_clicked()
+{
+ acceptTemporaryWithTimeout(QDateTime::currentDateTime().addDays(2));
+}
+
+#include <QRandomGenerator>
+
+void CertificateSelectionDialog::acceptTemporaryWithTimeout(QDateTime timeout)
+{
+ QRandomGenerator rng;
+
+ char items[8];
+ for(auto & c : items) {
+ c = rng.bounded(std::numeric_limits<char>::min(), std::numeric_limits<char>::max());
+ }
+
+ this->cryto_identity = CertificateHelper::createNewIdentity(
+ QByteArray(items, sizeof items).toBase64(QByteArray::OmitTrailingEquals),
+ timeout);
+
+ this->accept();
+}
diff --git a/src/certificateselectiondialog.hpp b/src/certificateselectiondialog.hpp
new file mode 100644
index 0000000..55fe909
--- /dev/null
+++ b/src/certificateselectiondialog.hpp
@@ -0,0 +1,46 @@
+#ifndef CERTIFICATESELECTIONDIALOG_HPP
+#define CERTIFICATESELECTIONDIALOG_HPP
+
+#include <QDialog>
+
+#include "cryptoidentity.hpp"
+
+namespace Ui {
+class CertificateSelectionDialog;
+}
+
+class CertificateSelectionDialog : public QDialog
+{
+ Q_OBJECT
+
+public:
+ explicit CertificateSelectionDialog(QWidget *parent = nullptr);
+ ~CertificateSelectionDialog();
+
+ void setServerQuery(QString const & query);
+
+ CryptoIdentity identity() const;
+
+private slots:
+ void on_use_temp_cert_30m_clicked();
+
+ void on_use_temp_cert_1h_clicked();
+
+ void on_use_temp_cert_12h_clicked();
+
+ void on_use_temp_cert_24h_clicked();
+
+ void on_use_temp_cert_48h_clicked();
+
+private:
+ //! Creates an anonymous identity with a randomly chosen name that
+ //! will time out on `timeout`, then accepts the dialog.
+ void acceptTemporaryWithTimeout(QDateTime timeout);
+
+private:
+ Ui::CertificateSelectionDialog *ui;
+
+ CryptoIdentity cryto_identity;
+};
+
+#endif // CERTIFICATESELECTIONDIALOG_HPP
diff --git a/src/certificateselectiondialog.ui b/src/certificateselectiondialog.ui
new file mode 100644
index 0000000..d7179ae
--- /dev/null
+++ b/src/certificateselectiondialog.ui
@@ -0,0 +1,154 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>CertificateSelectionDialog</class>
+ <widget class="QDialog" name="CertificateSelectionDialog">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>474</width>
+ <height>355</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Select client certificate</string>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout">
+ <item>
+ <widget class="QLabel" name="label">
+ <property name="text">
+ <string>Select existing certificate:</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLabel" name="server_request">
+ <property name="font">
+ <font>
+ <weight>75</weight>
+ <bold>true</bold>
+ </font>
+ </property>
+ <property name="text">
+ <string>TextLabel</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QTreeView" name="treeView"/>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout_2">
+ <item>
+ <widget class="QPushButton" name="create_new_cert">
+ <property name="text">
+ <string>Create new identity</string>
+ </property>
+ <property name="icon">
+ <iconset resource="icons.qrc">
+ <normaloff>:/icons/plus.svg</normaloff>:/icons/plus.svg</iconset>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer name="horizontalSpacer">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QPushButton" name="use_selected_cert">
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="text">
+ <string>Use</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <widget class="QLabel" name="label_2">
+ <property name="text">
+ <string>Create transient session certificate:</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout">
+ <item>
+ <widget class="QPushButton" name="use_temp_cert_30m">
+ <property name="text">
+ <string>30 Minutes</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="use_temp_cert_1h">
+ <property name="text">
+ <string>1 Hour</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="use_temp_cert_12h">
+ <property name="text">
+ <string>12 Hours</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="use_temp_cert_24h">
+ <property name="text">
+ <string>24 Hours</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="use_temp_cert_48h">
+ <property name="text">
+ <string>48 Hours</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <widget class="QDialogButtonBox" name="buttonBox">
+ <property name="standardButtons">
+ <set>QDialogButtonBox::Cancel</set>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <resources>
+ <include location="icons.qrc"/>
+ </resources>
+ <connections>
+ <connection>
+ <sender>buttonBox</sender>
+ <signal>rejected()</signal>
+ <receiver>CertificateSelectionDialog</receiver>
+ <slot>reject()</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>236</x>
+ <y>333</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>236</x>
+ <y>177</y>
+ </hint>
+ </hints>
+ </connection>
+ </connections>
+</ui>
diff --git a/src/cryptoidentity.cpp b/src/cryptoidentity.cpp
new file mode 100644
index 0000000..921a422
--- /dev/null
+++ b/src/cryptoidentity.cpp
@@ -0,0 +1,2 @@
+#include "cryptoidentity.hpp"
+
diff --git a/src/cryptoidentity.hpp b/src/cryptoidentity.hpp
new file mode 100644
index 0000000..a5fbb7f
--- /dev/null
+++ b/src/cryptoidentity.hpp
@@ -0,0 +1,24 @@
+#ifndef CRYPTOIDENTITIY_HPP
+#define CRYPTOIDENTITIY_HPP
+
+#include <QObject>
+
+#include <QSslCertificate>
+#include <QSslKey>
+
+//! Cryptographic user identitiy consisting
+//! of a key-certificate pair and some user information.
+struct CryptoIdentity
+{
+ QSslCertificate certificate;
+ QSslKey private_key;
+ QString display_name;
+
+ bool is_persistent = false;
+
+ bool isValid() const {
+ return (not this->certificate.isNull()) and (not this->private_key.isNull());
+ }
+};
+
+#endif // CRYPTOIDENTITIY_HPP
diff --git a/src/geminiclient.cpp b/src/geminiclient.cpp
index 0809120..e3036ce 100644
--- a/src/geminiclient.cpp
+++ b/src/geminiclient.cpp
@@ -1,6 +1,7 @@
#include "geminiclient.hpp"
#include <cassert>
#include <QDebug>
+#include <QSslConfiguration>
GeminiClient::GeminiClient(QObject *parent) : QObject(parent)
{
@@ -9,6 +10,14 @@ GeminiClient::GeminiClient(QObject *parent) : QObject(parent)
connect(&socket, &QSslSocket::disconnected, this, &GeminiClient::socketDisconnected);
connect(&socket, QOverload<const QList<QSslError> &>::of(&QSslSocket::sslErrors), this, &GeminiClient::sslErrors);
connect(&socket, QOverload<QAbstractSocket::SocketError>::of(&QSslSocket::error), this, &GeminiClient::socketError);
+
+
+ QSslConfiguration ssl_config;
+ ssl_config.setProtocol(QSsl::TlsV1_2);
+ // ssl_config.setLocalCertificate(QSslCertificate::1
+
+ socket.setSslConfiguration(ssl_config);
+
}
GeminiClient::~GeminiClient()
@@ -53,6 +62,18 @@ bool GeminiClient::cancelRequest()
return true;
}
+void GeminiClient::enableClientCertificate(const CryptoIdentity &ident)
+{
+ this->socket.setLocalCertificate(ident.certificate);
+ this->socket.setPrivateKey(ident.private_key);
+}
+
+void GeminiClient::disableClientCertificate()
+{
+ this->socket.setLocalCertificate(QSslCertificate{});
+ this->socket.setPrivateKey(QSslKey { });
+}
+
void GeminiClient::socketEncrypted()
{
QString request = target_url.toString(QUrl::FormattingOptions(QUrl::FullyEncoded)) + "\r\n";
diff --git a/src/geminiclient.hpp b/src/geminiclient.hpp
index 2578102..67e767b 100644
--- a/src/geminiclient.hpp
+++ b/src/geminiclient.hpp
@@ -6,6 +6,8 @@
#include <QSslSocket>
#include <QUrl>
+#include "cryptoidentity.hpp"
+
enum class TemporaryFailure {
unspecified,
server_unavailable,
@@ -44,6 +46,9 @@ public:
bool cancelRequest();
+ void enableClientCertificate(CryptoIdentity const & ident);
+ void disableClientCertificate();
+
signals:
void requestProgress(qint64 transferred);
diff --git a/src/icons.qrc b/src/icons.qrc
index 22c2d11..12e429a 100644
--- a/src/icons.qrc
+++ b/src/icons.qrc
@@ -34,8 +34,8 @@
<file>icons/gopher/telnet.svg</file>
<file>icons/gopher/text.svg</file>
<file>icons/info.svg</file>
- <file>about/help.gemini</file>
- <file>about/easter-egg.gemini</file>
<file>icons/help-box.svg</file>
+ <file>icons/shield-outline.svg</file>
+ <file>icons/shield-lock.svg</file>
</qresource>
</RCC>
diff --git a/src/icons/shield-lock.svg b/src/icons/shield-lock.svg
new file mode 100644
index 0000000..b4def0f
--- /dev/null
+++ b/src/icons/shield-lock.svg
@@ -0,0 +1 @@
+<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="24" height="24" viewBox="0 0 24 24"><path d="M12,1L3,5V11C3,16.55 6.84,21.74 12,23C17.16,21.74 21,16.55 21,11V5L12,1M12,7C13.4,7 14.8,8.1 14.8,9.5V11C15.4,11 16,11.6 16,12.3V15.8C16,16.4 15.4,17 14.7,17H9.2C8.6,17 8,16.4 8,15.7V12.2C8,11.6 8.6,11 9.2,11V9.5C9.2,8.1 10.6,7 12,7M12,8.2C11.2,8.2 10.5,8.7 10.5,9.5V11H13.5V9.5C13.5,8.7 12.8,8.2 12,8.2Z" /></svg> \ No newline at end of file
diff --git a/src/icons/shield-outline.svg b/src/icons/shield-outline.svg
new file mode 100644
index 0000000..c46cd12
--- /dev/null
+++ b/src/icons/shield-outline.svg
@@ -0,0 +1 @@
+<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="24" height="24" viewBox="0 0 24 24"><path d="M21,11C21,16.55 17.16,21.74 12,23C6.84,21.74 3,16.55 3,11V5L12,1L21,5V11M12,21C15.75,20 19,15.54 19,11.22V6.3L12,3.18L5,6.3V11.22C5,15.54 8.25,20 12,21Z" /></svg> \ No newline at end of file
diff --git a/src/kristall.pro b/src/kristall.pro
index 0321179..91aabf2 100644
--- a/src/kristall.pro
+++ b/src/kristall.pro
@@ -18,12 +18,17 @@ DEFINES += QT_DEPRECATED_WARNINGS
QMAKE_CFLAGS += -Wno-unused-parameter
QMAKE_CXXFLAGS += -Wno-unused-parameter
+LIBS += -lcrypto
+
INCLUDEPATH += $$PWD/../lib/luis-l-gist/
DEPENDPATH += $$PWD/../lib/luis-l-gist/
SOURCES += \
../lib/luis-l-gist/interactiveview.cpp \
browsertab.cpp \
+ certificatehelper.cpp \
+ certificateselectiondialog.cpp \
+ cryptoidentity.cpp \
documentoutlinemodel.cpp \
documentstyle.cpp \
favouritecollection.cpp \
@@ -45,6 +50,9 @@ SOURCES += \
HEADERS += \
../lib/luis-l-gist/interactiveview.hpp \
browsertab.hpp \
+ certificatehelper.hpp \
+ certificateselectiondialog.hpp \
+ cryptoidentity.hpp \
documentoutlinemodel.hpp \
documentstyle.hpp \
favouritecollection.hpp \
@@ -65,6 +73,7 @@ HEADERS += \
FORMS += \
browsertab.ui \
+ certificateselectiondialog.ui \
mainwindow.ui \
mediaplayer.ui \
settingsdialog.ui
@@ -79,6 +88,7 @@ else: unix:!android: target.path = /opt/$${TARGET}/bin
RESOURCES += \
../lib/BreezeStyleSheets/breeze.qrc \
+ builtins.qrc \
icons.qrc
DISTFILES += \
diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp
index 7f668db..4cd1919 100644
--- a/src/mainwindow.cpp
+++ b/src/mainwindow.cpp
@@ -367,7 +367,7 @@ void MainWindow::on_actionGo_to_home_triggered()
{
BrowserTab * tab = qobject_cast<BrowserTab*>(this->ui->browser_tabs->currentWidget());
if(tab != nullptr) {
- tab->navigateTo(QUrl(global_settings.value("start_page").toString()), BrowserTab::PushAfterSuccess);
+ tab->navigateTo(QUrl(global_settings.value("start_page").toString()), BrowserTab::PushImmediate);
}
}