Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. QML and Qt Quick
  4. Add client certificate to QQuickWebEngineProfile clientCertificateStore in QML
Forum Updated to NodeBB v4.3 + New Features

Add client certificate to QQuickWebEngineProfile clientCertificateStore in QML

Scheduled Pinned Locked Moved Unsolved QML and Qt Quick
14 Posts 3 Posters 1.4k Views 1 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • N Offline
    N Offline
    notawhiteowl
    wrote on last edited by
    #1

    There is something I am not understanding. I have a qml file that contains:

    WebEngineView
      {
        id: web
        objectName: "web"
        settings.errorPageEnabled: false
        settings.localContentCanAccessRemoteUrls: true
        profile.httpUserAgent: components.system.getUserAgent()
        url: mainWindow.webUrl
        focus: true
        property string currentHoveredUrl: ""
        onLinkHovered: web.currentHoveredUrl = hoveredUrl
        width: mainWindow.width
        height: mainWindow.height
    

    profile is a QQuickWebEngineProfile
    but profile.clientCertificateStore() is not a function and profile.clientCertificateStore is undefined.
    this is in spite of

    https://doc.qt.io/qt-5/qquickwebengineprofile.html
    

    clearly stating that it's a public function.
    can somebody please give me an example of a qml snippet that loads a client keypair into the client store? what am I not understanding? I'm simply trying to read pem .crt and .key files from disk into the client keystore. where can i find an example of this?

    eyllanescE 1 Reply Last reply
    0
    • fcarneyF Offline
      fcarneyF Offline
      fcarney
      wrote on last edited by
      #2

      @notawhiteowl said in Add client certificate to QQuickWebEngineProfile clientCertificateStore in QML:

      clientCertificateStore

      WebEngineProfile != QQuickWebEngineProfile

      C++ is a perfectly valid school of magic.

      eyllanescE N 2 Replies Last reply
      0
      • N notawhiteowl

        There is something I am not understanding. I have a qml file that contains:

        WebEngineView
          {
            id: web
            objectName: "web"
            settings.errorPageEnabled: false
            settings.localContentCanAccessRemoteUrls: true
            profile.httpUserAgent: components.system.getUserAgent()
            url: mainWindow.webUrl
            focus: true
            property string currentHoveredUrl: ""
            onLinkHovered: web.currentHoveredUrl = hoveredUrl
            width: mainWindow.width
            height: mainWindow.height
        

        profile is a QQuickWebEngineProfile
        but profile.clientCertificateStore() is not a function and profile.clientCertificateStore is undefined.
        this is in spite of

        https://doc.qt.io/qt-5/qquickwebengineprofile.html
        

        clearly stating that it's a public function.
        can somebody please give me an example of a qml snippet that loads a client keypair into the client store? what am I not understanding? I'm simply trying to read pem .crt and .key files from disk into the client keystore. where can i find an example of this?

        eyllanescE Offline
        eyllanescE Offline
        eyllanesc
        wrote on last edited by
        #3

        @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);
        
        N 1 Reply Last reply
        0
        • fcarneyF fcarney

          @notawhiteowl said in Add client certificate to QQuickWebEngineProfile clientCertificateStore in QML:

          clientCertificateStore

          WebEngineProfile != QQuickWebEngineProfile

          eyllanescE Offline
          eyllanescE Offline
          eyllanesc
          wrote on last edited by
          #4

          @fcarney WebEngineProfile inherits from QQuickWebEngineProfile so profile is a WebEngineProfile and also a QQuickWebEngineProfile.

          1 Reply Last reply
          0
          • fcarneyF fcarney

            @notawhiteowl said in Add client certificate to QQuickWebEngineProfile clientCertificateStore in QML:

            clientCertificateStore

            WebEngineProfile != QQuickWebEngineProfile

            N Offline
            N Offline
            notawhiteowl
            wrote on last edited by
            #5

            @fcarney In the qml file, for example, if I console.log(profile) in the qml file it logs QQuickWebEngineProfile(0x55f1064907f0)

            So, I believe that profile here is a qquickwebengineprofile.
            that same profile 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 function QWebEngineClientCertificateStore * 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.cpp

            If 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?

            1 Reply Last reply
            0
            • fcarneyF Offline
              fcarneyF Offline
              fcarney
              wrote on last edited by
              #6

              They may be the same object, but it doesn't expose that to QML. The APIs are different between QML and C++. You are looking at C++ docs and wondering why it doesn't work in QML.

              C++ is a perfectly valid school of magic.

              1 Reply Last reply
              0
              • eyllanescE eyllanesc

                @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);
                
                N Offline
                N Offline
                notawhiteowl
                wrote on last edited by
                #7

                @eyllanesc I sent you an email to see if you have availability coming up. hoping it didnt go to spam.

                eyllanescE 2 Replies Last reply
                0
                • N notawhiteowl

                  @eyllanesc I sent you an email to see if you have availability coming up. hoping it didnt go to spam.

                  eyllanescE Offline
                  eyllanescE Offline
                  eyllanesc
                  wrote on last edited by
                  #8
                  This post is deleted!
                  1 Reply Last reply
                  0
                  • N notawhiteowl

                    @eyllanesc I sent you an email to see if you have availability coming up. hoping it didnt go to spam.

                    eyllanescE Offline
                    eyllanescE Offline
                    eyllanesc
                    wrote on last edited by
                    #9

                    @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.

                    1 Reply Last reply
                    0
                    • fcarneyF Offline
                      fcarneyF Offline
                      fcarney
                      wrote on last edited by
                      #10

                      Would have QML != C++ been more clear?

                      C++ is a perfectly valid school of magic.

                      N 1 Reply Last reply
                      0
                      • fcarneyF fcarney

                        Would have QML != C++ been more clear?

                        N Offline
                        N Offline
                        notawhiteowl
                        wrote on last edited by notawhiteowl
                        #11

                        @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?

                        1 Reply Last reply
                        0
                        • fcarneyF Offline
                          fcarneyF Offline
                          fcarney
                          wrote on last edited by
                          #12

                          @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.

                          C++ is a perfectly valid school of magic.

                          N 1 Reply Last reply
                          0
                          • fcarneyF fcarney

                            @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.

                            N Offline
                            N Offline
                            notawhiteowl
                            wrote on last edited by notawhiteowl
                            #13

                            @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.

                            1. What is the reason for this discrepancy?
                            2. Why is selectClientCertificate not firing in my application, when the server is known-working?
                            3. Is my goal of using the in-memory store reasonable in this application?
                            1 Reply Last reply
                            0
                            • N Offline
                              N Offline
                              notawhiteowl
                              wrote on last edited by
                              #14

                              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

                              1 Reply Last reply
                              0

                              • Login

                              • Login or register to search.
                              • First post
                                Last post
                              0
                              • Categories
                              • Recent
                              • Tags
                              • Popular
                              • Users
                              • Groups
                              • Search
                              • Get Qt Extensions
                              • Unsolved