Merge branch 'master' of ssh://pumpa.branchable.com
[larjonas-pumpa.git] / src / oauthwizard.cpp
blob84068f233982be0bc95e693e61bc641807284f9e
1 /*
2 Copyright 2013-2015 Mats Sjöberg
4 This file is part of the Pumpa programme.
6 Pumpa is free software: you can redistribute it and/or modify it
7 under the terms of the GNU General Public License as published by
8 the Free Software Foundation, either version 3 of the License, or
9 (at your option) any later version.
11 Pumpa is distributed in the hope that it will be useful, but WITHOUT
12 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13 or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
14 License for more details.
16 You should have received a copy of the GNU General Public License
17 along with Pumpa. If not, see <http://www.gnu.org/licenses/>.
20 #include <QDebug>
21 #include <QRegExp>
22 #include <QLineEdit>
23 #include <QCheckBox>
24 #include <QByteArray>
25 #include <QVBoxLayout>
26 #include <QMessageBox>
27 #include <QVariantMap>
28 #include <QApplication>
29 #include <QNetworkReply>
30 #include <QNetworkRequest>
32 #include "pumpa_defines.h"
33 #include "oauthwizard.h"
34 #include "util.h"
35 #include "json.h"
37 #define EXAMPLE_ACCOUNT_ID "username@example.com"
39 //------------------------------------------------------------------------------
41 OAuthFirstPage::OAuthFirstPage(QWidget* parent) :
42 QWizardPage(parent)
44 setTitle(tr("Welcome to Pumpa!"));
46 QVBoxLayout* layout = new QVBoxLayout(this);
48 QLabel* infoLabel =
49 new QLabel(tr("<p>In order to use pump.io you need to first register an "
50 "account with a pump.io server. If you haven't done this yet "
51 "you can do it now by trying out one of the existing public "
52 "servers: <br /><a href=\"http://pump.io/tryit.html\">"
53 "http://pump.io/tryit.html</a>.</p>"
54 "<p>When you are done enter your new pump.io account id "
55 "below in the form of <b>username@servername</b>.</p>"),
56 this);
57 infoLabel->setOpenExternalLinks(true);
58 infoLabel->setTextInteractionFlags(Qt::TextSelectableByMouse |
59 Qt::LinksAccessibleByMouse);
60 infoLabel->setWordWrap(true);
61 layout->addWidget(infoLabel);
62 layout->addStretch();
64 m_messageLabel = new QLabel(this);
65 layout->addWidget(m_messageLabel);
67 QLabel* accountIdLabel =
68 new QLabel(tr("<b>Your pump.io account id:</b>"), this);
69 QLineEdit* accountIdEdit = new QLineEdit(EXAMPLE_ACCOUNT_ID, this);
70 accountIdLabel->setBuddy(accountIdEdit);
71 connect(accountIdEdit, SIGNAL(textEdited(const QString&)),
72 this, SIGNAL(completeChanged()));
74 QCheckBox* sslCheckBox =
75 new QCheckBox(tr("Use secure connection (recommended)"), this);
76 sslCheckBox->setChecked(true);
78 layout->addWidget(accountIdLabel);
79 layout->addWidget(accountIdEdit);
80 layout->addWidget(sslCheckBox);
82 registerField("accountId*", accountIdEdit);
83 registerField("useSsl*", sslCheckBox);
85 setButtonText(QWizard::CommitButton, tr("Next"));
86 setCommitPage(true);
87 setLayout(layout);
90 //------------------------------------------------------------------------------
92 void OAuthFirstPage::setMessage(QString msg) {
93 m_messageLabel->setText(msg);
96 //------------------------------------------------------------------------------
98 bool OAuthFirstPage::splitAccountId(QString& username, QString& server) const {
99 QString accountId = field("accountId").toString().trimmed();
101 if (accountId == EXAMPLE_ACCOUNT_ID)
102 return false;
104 return splitWebfingerId(accountId, username, server);
107 //------------------------------------------------------------------------------
109 bool OAuthFirstPage::isComplete() const {
110 QString username, server;
111 return splitAccountId(username, server);
114 //------------------------------------------------------------------------------
116 bool OAuthFirstPage::validatePage() {
117 QString username, server;
118 bool ok = splitAccountId(username, server);
120 if (!ok)
121 return false;
123 emit committed(username, server);
124 return true;
127 //------------------------------------------------------------------------------
129 OAuthSecondPage::OAuthSecondPage(QWidget* parent) : QWizardPage(parent) {
130 setTitle(tr("Authorise Pumpa"));
132 QVBoxLayout* layout = new QVBoxLayout(this);
134 QLabel* infoLabel =
135 new QLabel(tr("In order for Pumpa to be able to read and post new messages "
136 "to your pump.io account you need to grant Pumpa access via "
137 "the web page. Pumpa will open the web page for you - just "
138 "follow the instructions and copy &amp; paste the "
139 "<b>verifier</b> text string back into the field below. (The "
140 "token should be automatically pre-filled.)"),
141 this);
142 infoLabel->setWordWrap(true);
143 layout->addWidget(infoLabel);
145 QLabel* tokenLabel = new QLabel(tr("Token:"), this);
146 QLineEdit* tokenEdit = new QLineEdit(this);
147 tokenLabel->setBuddy(tokenEdit);
148 layout->addWidget(tokenLabel);
149 layout->addWidget(tokenEdit);
151 QLabel* verifierLabel = new QLabel(tr("Verifier:"), this);
152 QLineEdit* verifierEdit = new QLineEdit(this);
153 verifierLabel->setBuddy(verifierEdit);
154 layout->addWidget(verifierLabel);
155 layout->addWidget(verifierEdit);
157 registerField("token*", tokenEdit);
158 registerField("verifier*", verifierEdit);
160 setLayout(layout);
163 //------------------------------------------------------------------------------
165 bool OAuthSecondPage::validatePage() {
166 QString token = field("token").toString();
167 QString verifier = field("verifier").toString();
169 if (token.isEmpty() || verifier.isEmpty())
170 return false;
172 emit committed(token, verifier);
173 return true;
176 //------------------------------------------------------------------------------
178 OAuthWizard::OAuthWizard(QNetworkAccessManager* nam, KQOAuthManager* oam,
179 QWidget* parent) :
180 QWizard(parent),
181 m_oam(oam),
182 m_nam(nam)
184 setWindowTitle(CLIENT_FANCY_NAME);
186 m_oar = new KQOAuthRequest(this);
188 p1 = new OAuthFirstPage(this);
189 p2 = new OAuthSecondPage(this);
191 connect(p1, SIGNAL(committed(QString, QString)),
192 this, SLOT(onFirstPageCommitted(QString, QString)));
193 connect(p2, SIGNAL(committed(QString, QString)),
194 this, SLOT(onSecondPageCommitted(QString, QString)));
196 addPage(p1);
197 addPage(p2);
200 //------------------------------------------------------------------------------
202 void OAuthWizard::notifyMessage(QString msg) {
203 qDebug() << "[OAuthWizard]" << msg;
206 //------------------------------------------------------------------------------
208 void OAuthWizard::errorMessage(QString msg) {
209 p1->setMessage("<b><font color=\"red\">"+msg+"</font></b>");
210 qDebug() << "[OAuthWizard ERROR]" << msg;
211 back();
214 //------------------------------------------------------------------------------
216 void OAuthWizard::onFirstPageCommitted(QString username, QString server) {
217 m_username = username;
218 m_server = siteUrlFixer(server, field("useSsl").toBool());
219 m_clientRegTryCount = 0;
220 registerOAuthClient();
223 //------------------------------------------------------------------------------
225 void OAuthWizard::registerOAuthClient() {
226 notifyMessage(tr("Registering client ..."));
227 m_clientRegTryCount++;
229 QUrl serverUrl(m_server);
230 serverUrl.setPath("/api/client/register");
231 qDebug() << serverUrl;
233 QNetworkRequest req;
234 req.setUrl(serverUrl);
235 req.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
237 QVariantMap post;
238 post["type"] = "client_associate";
239 post["application_type"] = "native";
240 post["application_name"] = CLIENT_FANCY_NAME;
241 post["logo_uri"] = "http://saz.im/images/pumpa.png";
243 QByteArray postData = serializeJson(post);
245 // qDebug() << "data=" << postData;
247 QNetworkReply *reply = m_nam->post(req, postData);
249 connect(reply, SIGNAL(finished()), this, SLOT(onOAuthClientRegDone()));
252 //------------------------------------------------------------------------------
254 void OAuthWizard::onOAuthClientRegDone() {
255 QNetworkReply *reply = qobject_cast<QNetworkReply *>(sender());
256 if (reply->error() != QNetworkReply::NoError) {
257 errorMessage(tr("Network error: ") + reply->errorString());
258 return;
261 QByteArray data = reply->readAll();
263 QVariantMap json = parseJson(data);
264 m_clientId = json["client_id"].toString();
265 m_clientSecret = json["client_secret"].toString();
267 emit clientRegistered(m_username, m_server, m_clientId, m_clientSecret);
269 notifyMessage(QString(tr("Registered client to [%1] successfully.")).
270 arg(m_server));
272 getOAuthAccess();
275 //------------------------------------------------------------------------------
277 void OAuthWizard::getOAuthAccess() {
278 notifyMessage(tr("Authorising user ..."));
280 connect(m_oam, SIGNAL(temporaryTokenReceived(QString, QString)),
281 this, SLOT(onTemporaryTokenReceived(QString, QString)));
282 connect(m_oam, SIGNAL(accessTokenReceived(QString, QString)),
283 this, SLOT(onAccessTokenReceived(QString, QString)));
285 m_oar->initRequest(KQOAuthRequest::TemporaryCredentials,
286 QUrl(m_server+"/oauth/request_token"));
287 m_oar->setConsumerKey(m_clientId);
288 m_oar->setConsumerSecretKey(m_clientSecret);
290 m_oam->executeRequest(m_oar);
293 //------------------------------------------------------------------------------
295 void OAuthWizard::onTemporaryTokenReceived(QString token,
296 QString /*tokenSecret*/) {
297 setField("token", token);
298 QUrl userAuthURL(m_server+"/oauth/authorize");
299 if (m_oam->lastError() == KQOAuthManager::NoError)
300 m_oam->getUserAuthorization(userAuthURL);
301 else
302 errorMessage(tr("Network or authentication error!"));
305 //------------------------------------------------------------------------------
307 void OAuthWizard::onSecondPageCommitted(QString token, QString verifier) {
308 m_oam->verifyToken(token, verifier);
309 m_oam->getUserAccessTokens(QUrl(m_server+"/oauth/access_token"));
312 //------------------------------------------------------------------------------
314 void OAuthWizard::onAccessTokenReceived(QString token, QString tokenSecret) {
315 emit accessTokenReceived(token, tokenSecret);