kde-extraapps/kdeplasma-addons/dataengines/microblog/koauthwebhelper.cpp

219 lines
7.4 KiB
C++
Raw Normal View History

/*
* Copyright 2012 Sebastian Kügler <sebas@kde.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Library General Public License as
* published by the Free Software Foundation; either version 2 or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details
*
* You should have received a copy of the GNU Library General Public
* License along with this program; if not, write to the
* Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
/*
* QOAuth example
* http://blog.ayoy.net/2009/6/24/oauth
*
* Twitter OAuth Docs:
* https://dev.twitter.com/docs/auth/oauth
*
* How does OAuth work diagram:
* https://dev.twitter.com/sites/default/files/images_documentation/oauth_diagram.png
*
*
*/
#include <QUrl>
#include <KRun>
#include <KDialog>
#include <KWebView>
#include <KWebPage>
#include <QWebElement>
#include <QWebFrame>
#include <QWebPage>
#include <QNetworkAccessManager>
#include <QNetworkCookieJar>
#include "koauthwebhelper.h"
#include <KDebug>
namespace KOAuth {
class KOAuthWebHelperPrivate {
public:
KOAuthWebHelperPrivate()
{
webView = 0;
dialog = 0;
busy = false;
}
QString user;
QString password;
QString serviceBaseUrl;
QHash<QString, QString> authorizeUrls;
QWebView *webView;
KDialog *dialog;
bool busy;
QTimer *timer;
};
KOAuthWebHelper::KOAuthWebHelper(QObject* parent)
: QObject(parent),
d(new KOAuthWebHelperPrivate)
{
setObjectName(QLatin1String("QOAuthWebHelper"));
d->timer = new QTimer();
d->timer->setInterval(3000);
d->timer->setSingleShot(true);
connect(d->timer, SIGNAL(timeout()), SLOT(showDialog()));
}
KOAuthWebHelper::~KOAuthWebHelper()
{
kDebug();
delete d;
}
void KOAuthWebHelper::setUser(const QString& user)
{
d->user = user;
}
void KOAuthWebHelper::setPassword(const QString& password)
{
d->password = password;
}
void KOAuthWebHelper::setServiceBaseUrl(const QString &url)
{
d->serviceBaseUrl = url;
}
void KOAuthWebHelper::showDialog()
{
if (d->dialog) {
kDebug() << "Showing dialog for URL: " << d->webView->page()->mainFrame()->toHtml();
d->dialog->show();
}
}
void KOAuthWebHelper::authorizeApp(const QString &serviceBaseUrl, const QString &authorizeUrl, const QString &pageUrl)
{
Q_UNUSED(serviceBaseUrl);
Q_UNUSED(authorizeUrl);
if (d->serviceBaseUrl == "/" || d->serviceBaseUrl.isEmpty()) return;
if (!d->webView) {
d->dialog = new KDialog();
d->dialog->setCaption( "authorize application" );
d->dialog->setButtons( KDialog::Ok | KDialog::Cancel);
//d->webView = new KWebView(d->dialog, KWebPage::KIOIntegration);
d->webView = new QWebView(d->dialog);
d->dialog->setMainWidget(d->webView);
// d->dialog->show(); // remove
connect(d->webView->page(), SIGNAL(loadFinished(bool)), SLOT(loadFinished()));
}
// Set an empty cookiejar, we don't want to recycle already logged in users
QNetworkAccessManager *qnam = d->webView->page()->networkAccessManager();
QNetworkCookieJar *jar = new QNetworkCookieJar(this);
qnam->setCookieJar(jar);
d->authorizeUrls[authorizeUrl] = d->serviceBaseUrl;
d->webView->page()->mainFrame()->load(pageUrl);
}
bool KOAuthWebHelper::isIdentica()
{
return d->serviceBaseUrl.toLower().contains("identi.ca");
}
void KOAuthWebHelper::loadFinished()
{
QWebPage *page = dynamic_cast<QWebPage*>(sender());
if (!page) {
return;
}
QWebFrame* mf = page->mainFrame();
QString u = page->mainFrame()->url().toString();
if (d->authorizeUrls.contains(u)) {
QString pin;
foreach (const QWebElement &code, mf->findAllElements("CODE")) {
pin = code.toPlainText();
// kDebug() << "tag:" << code.tagName() << "PIN:" << pin;
};
foreach (const QWebElement &code, mf->findAllElements("#oauth_pin")) {
pin = code.toPlainText();
// kDebug() << "tag:" << code.tagName() << "PIN:" << pin;
};
if (!isIdentica() || !pin.isEmpty()) {
// kDebug() << "We're done!" << u << pin;
d->timer->stop(); // No need to show the dialog. :)
emit statusUpdated(d->user, d->serviceBaseUrl, "Busy", "Application authorized");
emit appAuthSucceeded(u, pin);
if (d->dialog) {
d->dialog->close();
}
return;
}
} else {
// The remote service challenges app authorization, this means that the
// user has to log in to the remote site to retrieve a PIN back, which
// in turn will produce the accessToken and accessTokenSecret pair in
// the next, final authorization step.
emit statusUpdated(d->user, d->serviceBaseUrl, "Waiting", "App Authorization needed");
// we have to log in, let's see if we can do that automatically...
// For Twitter, there are two cases:
// - the user is already logged in, we just have to click the accept button
// - the user is not logged in, in that case the user/password have to be
// be filled in. We happen to know that, as it's the argument to the "auth"
// operation in the dataengine.
// kDebug() << "logging in " << d->user << d->password;
if (!isIdentica()) {
// Try to fill in user/pass into the form
//kDebug() << "twitter.com hacks JavaScript hacks: " << u;
QString script = "var userName = document.getElementById(\"username_or_email\"); userName.value = \"" + d->user + "\";\n";
script.append("var passWord = document.getElementById(\"password\"); passWord.value = \"" + d->password + "\";\n");
mf->evaluateJavaScript(script);
//kDebug() << "ran script 1: " << script;
// Evaluate the button click separately, as the above script might abort,
// and not all lines are actually executed.
script = QString();
script.append("var ackButton = document.getElementById(\"allow\"); ackButton.click();");
mf->evaluateJavaScript(script);
//kDebug() << "ran script 2: " << script;
} else if (d->serviceBaseUrl.toLower().contains("identi.ca")) {
//kDebug() << "Identi.ca hacks JavaScript hacks";
QVariant r;
QString script = "var userName = document.getElementById(\"nickname\"); userName.value = \"" + d->user + "\";\n";
script.append("var passWord = document.getElementById(\"password\"); passWord.value = \"" + d->password + "\";\n");
r = mf->evaluateJavaScript(script);
kDebug() << "Ran script 1" << script << r;
// Evaluate the button click separately, as the above script might abort,
// and not all lines are actually executed.
script = "";
script.append("var ackButton = document.getElementById(\"allow_submit\"); ackButton.click();");
r = mf->evaluateJavaScript(script);
kDebug() << "Ran script 2" << script << r;
}
d->timer->start();
}
}
}
#include "koauthwebhelper.moc"