From d3bd536be0affdbe28b0494d740f1e6f3d8044f8 Mon Sep 17 00:00:00 2001 From: John Maguire Date: Thu, 29 Nov 2012 17:28:47 +0100 Subject: [PATCH] Working dropbox authentication with oauth redirect. --- src/internet/dropboxauthenticator.cpp | 84 +++++++++++++++++++++++++++ src/internet/dropboxauthenticator.h | 13 +++++ 2 files changed, 97 insertions(+) diff --git a/src/internet/dropboxauthenticator.cpp b/src/internet/dropboxauthenticator.cpp index 1ff1ad59b..704dac996 100644 --- a/src/internet/dropboxauthenticator.cpp +++ b/src/internet/dropboxauthenticator.cpp @@ -2,7 +2,9 @@ #include +#include #include +#include #include "core/closure.h" #include "core/logging.h" @@ -14,6 +16,11 @@ static const char* kAppSecret = "pg7y68h5efap8r6"; static const char* kRequestTokenEndpoint = "https://api.dropbox.com/1/oauth/request_token"; +static const char* kAuthoriseEndpoint = + "https://www.dropbox.com/1/oauth/authorize"; +static const char* kAccessTokenEndpoint = + "https://api.dropbox.com/1/oauth/access_token"; + } // namespace DropboxAuthenticator::DropboxAuthenticator(QObject* parent) @@ -48,5 +55,82 @@ void DropboxAuthenticator::StartAuthorisation(const QString& email) { } void DropboxAuthenticator::RequestTokenFinished(QNetworkReply* reply) { + QString result = reply->readAll(); + QStringList components = result.split("&"); + QMap params; + foreach (const QString& component, components) { + QStringList pairs = component.split("="); + if (pairs.size() != 2) { + continue; + } + params[pairs[0]] = pairs[1]; + } + token_ = params["oauth_token"]; + secret_ = params["oauth_token_secret"]; + Authorise(); +} + +void DropboxAuthenticator::Authorise() { + server_.listen(QHostAddress::LocalHost); + const quint16 port = server_.serverPort(); + + NewClosure(&server_, SIGNAL(newConnection()), this, SLOT(NewConnection())); + + QUrl url(kAuthoriseEndpoint); + url.addQueryItem("oauth_token", token_); + url.addQueryItem("oauth_callback", QString("http://localhost:%1").arg(port)); + + QDesktopServices::openUrl(url); +} + +void DropboxAuthenticator::NewConnection() { + QTcpSocket* socket = server_.nextPendingConnection(); + server_.close(); + + QByteArray buffer; + NewClosure(socket, SIGNAL(readyRead()), + this, SLOT(RedirectArrived(QTcpSocket*, QByteArray)), socket, buffer); +} + +void DropboxAuthenticator::RedirectArrived(QTcpSocket* socket, QByteArray buffer) { + buffer.append(socket->readAll()); + if (socket->atEnd() || buffer.endsWith("\r\n\r\n")) { + socket->deleteLater(); + QList split = buffer.split('\r'); + const QByteArray& request_line = split[0]; + QUrl url(QString::fromAscii(request_line.split(' ')[1])); + uid_ = url.queryItemValue("uid"); + RequestAccessToken(); + } +} + +void DropboxAuthenticator::RequestAccessToken() { + QUrl url(kAccessTokenEndpoint); + typedef QPair Param; + + QByteArray signature = QUrl::toPercentEncoding( + QString("%1&%2").arg(kAppSecret, secret_)); + QList params; + params << Param("oauth_consumer_key", kAppKey) + << Param("oauth_signature_method", "PLAINTEXT") + << Param("oauth_timestamp", QString::number(time(NULL))) + << Param("oauth_nonce", QString::number(qrand())) + << Param("oauth_signature", signature) + << Param("oauth_token", token_); + QStringList encoded_params; + foreach (const Param& p, params) { + encoded_params << QString("%1=\"%2\"").arg(p.first, p.second); + } + QString authorisation_header = QString("OAuth ") + encoded_params.join(", "); + qLog(Debug) << authorisation_header; + QNetworkRequest request(url); + request.setRawHeader("Authorization", authorisation_header.toUtf8()); + + QNetworkReply* reply = network_->post(request, QByteArray()); + NewClosure(reply, SIGNAL(finished()), + this, SLOT(RequestAccessTokenFinished(QNetworkReply*)), reply); +} + +void DropboxAuthenticator::RequestAccessTokenFinished(QNetworkReply* reply) { qLog(Debug) << reply->readAll(); } diff --git a/src/internet/dropboxauthenticator.h b/src/internet/dropboxauthenticator.h index f8dea88a7..185e2e756 100644 --- a/src/internet/dropboxauthenticator.h +++ b/src/internet/dropboxauthenticator.h @@ -2,6 +2,7 @@ #define DROPBOXAUTHENTICATOR_H #include +#include class NetworkAccessManager; class QNetworkReply; @@ -14,9 +15,21 @@ class DropboxAuthenticator : public QObject { private slots: void RequestTokenFinished(QNetworkReply* reply); + void RedirectArrived(QTcpSocket* socket, QByteArray buffer); + void NewConnection(); + void RequestAccessTokenFinished(QNetworkReply* reply); + + private: + void Authorise(); + void RequestAccessToken(); private: NetworkAccessManager* network_; + QTcpServer server_; + + QString token_; + QString secret_; + QString uid_; }; #endif // DROPBOXAUTHENTICATOR_H