Add client certificate to QQuickWebEngineProfile clientCertificateStore in QML
-
@notawhiteowl said in Add client certificate to QQuickWebEngineProfile clientCertificateStore in QML:
clientCertificateStore
-
@notawhiteowl said in Add client certificate to QQuickWebEngineProfile clientCertificateStore in QML:
clientCertificateStore
@fcarney In the qml file, for example, if I
console.log(profile)
in the qml file it logsQQuickWebEngineProfile(0x55f1064907f0)
So, I believe that
profile
here is a qquickwebengineprofile.
that sameprofile
is being used successfully, elsewhere in the code, to set the user-agent in the WebEngineView, so I believe that QQuickWebEngineProfile profile is in fact the QQuickWebEngineProfile of the WebEngineView.... does this sound correct?
and according to the documentation link, that is the exact object which contains the public functionQWebEngineClientCertificateStore * clientCertificateStore()
So what am I missing?
I really appreciate you trying to help me, I'm sorry that my ignorance is the primary roadblock.The full QML is at: https://github.com/jellyfin/jellyfin-media-player/blob/master/src/ui/webview.qml
and I believe it's being instantiated here: https://github.com/jellyfin/jellyfin-media-player/blob/master/src/main.cppIf you wouldn't mind taking a glance at it and pointing me in the right direction, I'd really appreciate it. There is a dearth of real-world examples for this case.
The second question is this: Does QWebEngineClientCertificateSelection even access the in-memory keystore? Or will it only provide certificateOptions from the system store?
-
@notawhiteowl A possible solution is to create a QObject as a helper:
class Helper: public QObject{ public: using QObject; Q_INVOKABLE void foo(QQuickWebEngineProfile *profile){ // profile->clientCertificateStore(); } };
So I expose a Helper object as contextProperty:
Helper helper; engine()->rootContext()->setContextProperty("helper", &helper);
And then you use it in QML:
Component.onCompleted: helper.foo(web.profile);
@eyllanesc I sent you an email to see if you have availability coming up. hoping it didnt go to spam.
-
@eyllanesc I sent you an email to see if you have availability coming up. hoping it didnt go to spam.
-
@eyllanesc I sent you an email to see if you have availability coming up. hoping it didnt go to spam.
@notawhiteowl @notawhiteowl No, no problem. Just for this I have placed my signature, I will respond to you in a short time.
If you have an account in discord, we could talk more comfortably there. My account is eyllanesc#5911.
-
@fcarney i appreciate your comfort in these topics very much. bottom line, do you think it will be possible to implement the in-memory client keystore and utilize it in this case, or would it need to involve a major rewrite?
-
@notawhiteowl said in Add client certificate to QQuickWebEngineProfile clientCertificateStore in QML:
do you think it will be possible to implement the in-memory client keystore and utilize it in this case, or would it need to involve a major rewrite?
As @eyllanesc showed you will have to write your own c++ functions to expose that functionality to QML.
-
@notawhiteowl said in Add client certificate to QQuickWebEngineProfile clientCertificateStore in QML:
do you think it will be possible to implement the in-memory client keystore and utilize it in this case, or would it need to involve a major rewrite?
As @eyllanesc showed you will have to write your own c++ functions to expose that functionality to QML.
@fcarney Thank you for your input! We have gotten as far as this helper object.
#include <QGuiApplication> #include <QQmlApplicationEngine> #include <QQmlContext> #include <QSslCertificate> #include <QtWebEngine> class ClientCertificateHelper: public QObject{ Q_OBJECT public: using QObject::QObject; Q_INVOKABLE bool init(QQuickWebEngineProfile *profile){ QSslKey key; QSslCertificate certificate; QString pfx_path = "/path/to/client.pfx"; QFile file(pfx_path); if(!file.open(QFile::ReadOnly)){ return false; } if(QSslCertificate::importPkcs12(&file, &key, &certificate, nullptr, "exportpassword")){ profile->clientCertificateStore()->add(certificate, key); QLOG_DEBUG() << "Client certificate successfully loaded "+pfx_path; return true; } QLOG_DEBUG() << "FAILED to load client certificate from "+pfx_path; return false; } }; #include "main.moc" ... ... QObject::connect(engine, &QQmlApplicationEngine::objectCreated, [=](QObject* object, const QUrl& url) { Q_UNUSED(url); if (object == nullptr) throw FatalException(QObject::tr("Failed to parse application engine script.")); KonvergoWindow* window = Globals::MainWindow(); QObject* webChannel = qvariant_cast<QObject*>(window->property("webChannel")); Q_ASSERT(webChannel); ComponentManager::Get().setWebChannel(qobject_cast<QWebChannel*>(webChannel)); QObject::connect(uniqueApp, &UniqueApplication::otherApplicationStarted, window, &KonvergoWindow::otherAppFocus); }); engine->rootContext()->setContextProperty("clientCertificateHelper", &clientCertificateHelper); engine->load(QUrl(QStringLiteral("qrc:/ui/webview.qml"))); Log::UpdateLogLevel(); // run our application int ret = app.exec();
and have modified webview.qml thusly:
import QtQuick 2.15 import QtQuick.Window 2.15 import QtWebEngine 1.10 ... ... Component.onCompleted: { if (clientCertificateHelper.init(profile)) { console.log("Helper returned true") } else { console.log("Helper did not return true") } forceActiveFocus() mainWindow.reloadWebClient.connect(reload) } ... ... onSelectClientCertificate: function(selection) { console.log("CLIENT CERTIFICATE REQUESTED") selection.certificates[0].select(); }
So, the helper object returns true, the certificate constructor is happy, but selectClientCertificate is never fired.
So, I have three particular questions.
https://doc.qt.io/qt-5/qwebenginepage.html#selectClientCertificate
does not mention firing the signal based on in memory store,
but then https://doc.qt.io/Qt-5/qwebengineclientcertificatestore.html suggests that it does.- What is the reason for this discrepancy?
- Why is selectClientCertificate not firing in my application, when the server is known-working?
- Is my goal of using the in-memory store reasonable in this application?
-
ugh. I guess this feature has just been broken for over a year with misleading documentation. no big deal.
thanks for your help everybody.
https://bugreports.qt.io/browse/QTBUG-86132