Search code examples
javascriptqtqmlqt5qwebengineview

Qt5 and QML: How to automatically input username and password using WebEngine Quick Nano Browser


I am writing a small application using Qt and QML that uses the example in the Qt documentation WebEngine Quick Nano Browser.

In this example I am trying to access to my email. I can do it, but I am trying to enter username and password automatically so that I can instantly log into my emails.

Basically as an example, after launching the application (my email address is hard-coded) I can see the username page of gmail, but here I have to type my username to access to the next page that has the password::

username

Here I have to type my password:

pass

Only after doing that I can access to my email.

The Expected result would be as soon as I run the application, I would like to go straight to my email without inputting username and password

The code that I am running is the following:

#include <QtGui/QGuiApplication>
typedef QGuiApplication Application;
#include <QtQml/QQmlApplicationEngine>
#include <QtQml/QQmlContext>
#include <QtWebEngine/qtwebengineglobal.h>

static QUrl startupUrl()
{
    QUrl ret;
    QStringList args(qApp->arguments());
    args.takeFirst();
    for (const QString &arg : qAsConst(args)) {
        if (arg.startsWith(QLatin1Char('-')))
             continue;
        ret = Utils::fromUserInput(arg);
        if (ret.isValid())
            return ret;
    }

    // first email
    return QUrl(QStringLiteral("https://accounts.google.com/signin"));
}

int main(int argc, char **argv)
{
    QCoreApplication::setOrganizationName("QtExamples");
    QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);

    Application app(argc, argv);

    QtWebEngine::initialize();

    QQmlApplicationEngine appEngine;
    Utils utils;
    appEngine.rootContext()->setContextProperty("utils", &utils);
    appEngine.load(QUrl("qrc:/ApplicationRoot.qml"));
    QMetaObject::invokeMethod(appEngine.rootObjects().first(), "load", Q_ARG(QVariant, startupUrl()));

    return app.exec();
}

What I tried so far

  1. I have beed doing a lot of research and this source was useful in trying to understand the concept on how to hard code the entries. However, how do I proceed to the next passowrd page`?

  2. This is another example (although in php) of the same problem with a different approach. That also was useful to undertand the concept and the main idea.

  3. this additional source looks a very good example, although JavaScript is used here.

Now after reading much more information I found this post which makes me think that the best approach would be to integrate some JavaScript inside the QML code? I am a newbie in JavaScript if that would be the right route. And if this is the right thing, how can I do that?

I am considering to use QNetworkAccessManager in this application, but I am not sure how to best implement it.

Thanks to anyone who may have already gone through this or that may provide some guidance or an example to how implement this in the WebEngine Quick Nano Browser is very appreciated.


Solution

  • Do not use the example WebEngine Quick Nano Browser as I see it unnecessary and only distract from the background objective.

    The logic is to understand how google login works, in this case you must find a way to obtain the elements of the DOM using javascript for example through id, class, name, etc. and modify it according to the desired logic. Also note that the url changes so that in each one a different script must be executed.

    Considering the above, the solution is:

    import QtQuick 2.13
    import QtQuick.Controls 2.13
    import QtWebEngine 1.9
    
    ApplicationWindow{
        id: root
        width: 640
        height: 480
        visible: true
    
        property string username: "USERNAME"
        property string password: "PASSWORD"
    
        QtObject{
            id: internals
            property string script_username: "
                setTimeout(function() {
                    var input_username = document.getElementById('identifierId');
                    input_username.value = '%1';
                    var button = document.getElementById('identifierNext');
                    button.click();
                }, 1000);
            ".arg(username)
    
            property string script_password: "
                setTimeout(function() { 
                    var input_password = document.getElementsByName('password')[0];
                    input_password.value = '%1';
                    var button = document.getElementById('passwordNext');
                    button.click();
                }, 1000);
            ".arg(password)
        }
    
        WebEngineView {
            id: view
            anchors.fill: parent
            onUrlChanged: {
                if(url == "https://accounts.google.com/signin/v2/identifier?flowName=GlifWebSignIn&flowEntry=ServiceLogin"){
                    view.runJavaScript(internals.script_username)   
                }
                else if(url == "https://accounts.google.com/signin/v2/sl/pwd?flowName=GlifWebSignIn&flowEntry=ServiceLogin&cid=1&navigationDirection=forward"){
                    view.runJavaScript(internals.script_password)
                }
            }
            Component.onCompleted: view.url = "https://accounts.google.com/signin"
        }
    }