First draft, credentials are still saved to settings
[situare] / src / facebookservice / facebookauthentication.cpp
1 /*
2    Situare - A location system for Facebook
3    Copyright (C) 2010  Ixonos Plc. Authors:
4
5        Ville Tiensuu - ville.tiensuu@ixonos.com
6        Kaj Wallin - kaj.wallin@ixonos.com
7        Henri Lampela - henri.lampela@ixonos.com
8
9    Situare is free software; you can redistribute it and/or
10    modify it under the terms of the GNU General Public License
11    version 2 as published by the Free Software Foundation.
12
13    Situare is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16    GNU General Public License for more details.
17
18    You should have received a copy of the GNU General Public License
19    along with Situare; if not, write to the Free Software
20    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,
21    USA.
22 */
23
24 #include <QtDebug>
25 #include <QDateTime>
26 #include <QSettings>
27 #include <QStringList>
28 #include <QVariantMap>
29
30 #ifdef Q_WS_MAEMO_5
31 #include <QMaemo5InformationBox>
32 #endif // Q_WS_MAEMO_5
33
34 #include "facebookauthentication.h"
35 #include "facebookcommon.h"
36 #include "../common.h"
37 #include "parser.h"
38
39 FacebookAuthentication::FacebookAuthentication(QObject *parent)
40     : QObject(parent),
41     m_loginAttempts(0)
42
43 {
44     qDebug() << __PRETTY_FUNCTION__;
45
46     readCredentials(m_loginCredentials);
47 }
48
49 void FacebookAuthentication::start()
50 {
51     qDebug() << __PRETTY_FUNCTION__;
52
53     if(!verifyCredentials(m_loginCredentials)) {
54         QStringList list;
55         list.append(FACEBOOK_LOGINBASE);
56         list.append(SITUARE_PUBLIC_FACEBOOKAPI_KEY);
57         list.append(INTERVAL1);
58         list.append(SITUARE_LOGIN_SUCCESS);
59         list.append(INTERVAL2);
60         list.append(SITUARE_LOGIN_FAILURE);
61         list.append(FACEBOOK_LOGIN_ENDING);
62
63         QSettings settings(DIRECTORY_NAME, FILE_NAME);
64
65         QString cookies = settings.value(COOKIES, EMPTY).toString();
66         if(!cookies.isEmpty()) {
67             emit loginUsingCookies();
68         }
69         else {
70             emit newLoginRequest(formLoginPageUrl(list));
71         }
72     }
73     else {
74         emit credentialsReady(false, m_loginCredentials);
75     }
76
77 }
78
79 bool FacebookAuthentication::updateCredentials(const QUrl &url)
80 {
81     qDebug() << __PRETTY_FUNCTION__;
82
83     bool found = false;
84
85     if (url.isValid()){
86          qDebug() << "url is valid";
87
88         QString callbackUrl = url.toString();
89         qDebug() << "callbackUrl:  " << callbackUrl.toAscii();
90
91         if (callbackUrl.indexOf(LOGIN_SUCCESS_REPLY) == 0) {
92             qDebug() << "login success";
93
94             // let's find out session credentials
95             if(callbackUrl.contains(SESSION_KEY)) {
96
97                 QJson::Parser parser;
98                 bool ok;
99
100                 // split string into string part and json part
101                 QStringList list = url.toString().split("=");
102
103                 for(int i=0;i<list.count();i++) {
104                     // if string starts with json item
105                     if(list.at(i).startsWith("{")) {
106                         QByteArray jsonString = list.at(i).toAscii();
107                         QVariantMap result = parser.parse (jsonString, &ok).toMap();
108                         if (!ok) {
109
110                             qFatal("An error occurred during parsing");
111                             exit (1);
112                         }
113                         qDebug() << "Session Key" << result[SESSION_KEY].toString();
114                         m_loginCredentials.setSessionKey(result[SESSION_KEY].toString());
115
116 //                        // commeted out until qjson parser can handle 64-bit integers
117 //                        qDebug() << "userID" << result[USER_ID].toString();
118 //                        m_loginCredentials.setUserID(result[USER_ID].toString().toAscii());
119
120                         // dirty fix, get user id from session_key
121                         QStringList list = result[SESSION_KEY].toString().split("-");
122                         m_loginCredentials.setUserID(list.at(1));
123                         qDebug() << m_loginCredentials.userID();
124
125                         qDebug() << "Expires" << result[EXPIRES].toString();
126                         m_loginCredentials.setExpires(result[EXPIRES].toString());
127
128                         qDebug() << "Session Secret" << result[SESSION_SECRET].toString();
129                         m_loginCredentials.setSessionSecret(result[SESSION_SECRET].toString());
130
131                         qDebug() << "Signature" << result[SIGNATURE].toString();
132                         m_loginCredentials.setSig(result[SIGNATURE].toString());
133                     }
134                 }
135                 found = true;
136                 emit saveCookiesRequest();
137             }
138             writeCredentials(m_loginCredentials);
139             emit credentialsReady(true, m_loginCredentials);
140         }
141         else if ( callbackUrl.indexOf(LOGIN_FAILURE_REPLY) == 0){
142             qWarning() << "login failure" << endl;
143             qDebug() << callbackUrl;
144             ++m_loginAttempts;
145             /* emit loginFailure for every second login attemps, since webview loads login
146                error page (loadingDone() signal is emitted) and we need to avoid that because
147                at this point we don't have new login parameters */
148             if(m_loginAttempts % 2) {
149                 emit loginFailure();
150             }
151         }
152         else if(callbackUrl.indexOf(LOGIN_PAGE) == 0) {
153             qDebug() << "correct loginPage";
154         }
155         else {
156             qDebug() << "totally wrong webPage";
157             // we should not get a wrong page at this point
158             emit loginFailure();
159         }
160     }
161     else {
162         qDebug() << " Loading of page failed invalid URL" << endl;
163         // we should not get a wrong page at this point
164         emit loginFailure();
165         return false;
166     }
167     return found;
168 }
169
170 void FacebookAuthentication::writeCredentials(const FacebookCredentials &credentials)
171 {
172     qDebug() << __PRETTY_FUNCTION__;
173     QSettings settings(DIRECTORY_NAME, FILE_NAME);
174
175     settings.setValue(SESSION_KEY, credentials.sessionKey());
176     settings.setValue(USER_ID, credentials.userID());
177     settings.setValue(EXPIRES, credentials.expires());
178     settings.setValue(SESSION_SECRET, credentials.sessionSecret());
179     settings.setValue(SIGNATURE, credentials.sig());
180 }
181
182 void FacebookAuthentication::readCredentials(FacebookCredentials &credentialsFromFile)
183 {
184     qDebug() << __PRETTY_FUNCTION__;
185
186     QSettings settings(DIRECTORY_NAME, FILE_NAME);
187
188     credentialsFromFile.setSessionKey(settings.value(SESSION_KEY, ERROR).toString());
189     credentialsFromFile.setUserID(settings.value(USER_ID, ERROR).toString());
190     credentialsFromFile.setExpires(settings.value(EXPIRES, ERROR).toString());
191     credentialsFromFile.setSessionSecret(settings.value(SESSION_SECRET, ERROR).toString());
192     credentialsFromFile.setSig(settings.value(SIGNATURE, ERROR).toString());
193 }
194
195  FacebookCredentials FacebookAuthentication::loginCredentials() const
196  {
197      qDebug() << __PRETTY_FUNCTION__;
198      return m_loginCredentials;
199  }
200
201  bool FacebookAuthentication::verifyCredentials(const FacebookCredentials &credentials) const
202  {
203      qDebug() << __PRETTY_FUNCTION__;
204
205      // if expires value is 0, then credentials are valid forever
206      if(credentials.expires() == "0") {
207          return true;
208      }
209      else {
210          const QString dateTimeFormat = "dd.MM.yyyy  hh:mm:ss";
211          QString expires = credentials.expires();
212          QDateTime expireTime;
213          expireTime.setTime_t(expires.toInt());
214          QString expiresString = expireTime.toString(dateTimeFormat);
215          qDebug() << expiresString.toAscii();
216
217          QDateTime currentTime;
218          currentTime = QDateTime::currentDateTime();
219          QString currentTimeString = currentTime.toString(dateTimeFormat);
220          qDebug() << currentTimeString.toAscii();
221
222          return currentTime < expireTime;
223      }
224  }
225
226  QUrl FacebookAuthentication::formLoginPageUrl(const QStringList &urlParts) const
227  {
228     qDebug() << __PRETTY_FUNCTION__;
229
230     return QUrl(urlParts.join(EMPTY));
231  }
232
233  void FacebookAuthentication::saveUsername(const QString &username)
234  {
235      qDebug() << __PRETTY_FUNCTION__;
236
237      QSettings settings(DIRECTORY_NAME, FILE_NAME);
238      settings.setValue(USERNAME, username);
239  }
240
241  const QString FacebookAuthentication::loadUsername()
242  {
243      qDebug() << __PRETTY_FUNCTION__;
244
245      QSettings settings(DIRECTORY_NAME, FILE_NAME);
246      return settings.value(USERNAME, EMPTY).toString();
247  }
248
249  void FacebookAuthentication::clearAccountInformation(bool keepUsername)
250  {
251      qDebug() << __PRETTY_FUNCTION__;
252
253      m_loginCredentials.clearCredentials();
254      QSettings settings(DIRECTORY_NAME, FILE_NAME);
255      if(!keepUsername) {
256         settings.remove(USERNAME);
257         settings.remove(COOKIES);
258      }
259      settings.remove(USER_ID);
260      settings.remove(SESSION_KEY);
261      settings.remove(SESSION_SECRET);
262      settings.remove(EXPIRES);
263      settings.remove(SIGNATURE);  
264
265      emit credentialsChanged(m_loginCredentials);
266  }