1 /*
2  * Copyright (C) by Daniel Molkentin <danimo@owncloud.com>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful, but
10  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
11  * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12  * for more details.
13  */
14 
15 #include "cookiejar.h"
16 
17 #include "configfile.h"
18 
19 #include <QFile>
20 #include <QDateTime>
21 #include <QLoggingCategory>
22 #include <QNetworkCookie>
23 #include <QDataStream>
24 #include <QDir>
25 
26 namespace OCC {
27 
28 Q_LOGGING_CATEGORY(lcCookieJar, "sync.cookiejar", QtInfoMsg)
29 
30 namespace {
31     const unsigned int JAR_VERSION = 23;
32 }
33 
operator <<(QDataStream & stream,const QList<QNetworkCookie> & list)34 QDataStream &operator<<(QDataStream &stream, const QList<QNetworkCookie> &list)
35 {
36     stream << JAR_VERSION;
37     stream << quint32(list.size());
38     for (int i = 0; i < list.size(); ++i)
39         stream << list.at(i).toRawForm();
40     return stream;
41 }
42 
operator >>(QDataStream & stream,QList<QNetworkCookie> & list)43 QDataStream &operator>>(QDataStream &stream, QList<QNetworkCookie> &list)
44 {
45     list.clear();
46 
47     quint32 version;
48     stream >> version;
49 
50     if (version != JAR_VERSION)
51         return stream;
52 
53     quint32 count;
54     stream >> count;
55     for (quint32 i = 0; i < count; ++i) {
56         QByteArray value;
57         stream >> value;
58         QList<QNetworkCookie> newCookies = QNetworkCookie::parseCookies(value);
59         if (newCookies.count() == 0 && value.length() != 0) {
60             qCWarning(lcCookieJar) << "CookieJar: Unable to parse saved cookie:" << value;
61         }
62         for (int j = 0; j < newCookies.count(); ++j)
63             list.append(newCookies.at(j));
64         if (stream.atEnd())
65             break;
66     }
67     return stream;
68 }
69 
CookieJar(QObject * parent)70 CookieJar::CookieJar(QObject *parent)
71     : QNetworkCookieJar(parent)
72 {
73 }
74 
~CookieJar()75 CookieJar::~CookieJar()
76 {
77 }
78 
setCookiesFromUrl(const QList<QNetworkCookie> & cookieList,const QUrl & url)79 bool CookieJar::setCookiesFromUrl(const QList<QNetworkCookie> &cookieList, const QUrl &url)
80 {
81     if (QNetworkCookieJar::setCookiesFromUrl(cookieList, url)) {
82         Q_EMIT newCookiesForUrl(cookieList, url);
83         return true;
84     }
85 
86     return false;
87 }
88 
cookiesForUrl(const QUrl & url) const89 QList<QNetworkCookie> CookieJar::cookiesForUrl(const QUrl &url) const
90 {
91     QList<QNetworkCookie> cookies = QNetworkCookieJar::cookiesForUrl(url);
92     qCDebug(lcCookieJar) << url << "requests:" << cookies;
93     return cookies;
94 }
95 
clearSessionCookies()96 void CookieJar::clearSessionCookies()
97 {
98     setAllCookies(removeExpired(allCookies()));
99 }
100 
save(const QString & fileName)101 bool CookieJar::save(const QString &fileName)
102 {
103     const QFileInfo info(fileName);
104     if (!info.dir().exists())
105     {
106         info.dir().mkpath(QStringLiteral("."));
107     }
108 
109     qCDebug(lcCookieJar) << fileName;
110     QFile file(fileName);
111     if (!file.open(QIODevice::WriteOnly))
112     {
113         return false;
114     }
115     QDataStream stream(&file);
116     stream << removeExpired(allCookies());
117     file.close();
118     return true;
119 }
120 
restore(const QString & fileName)121 bool CookieJar::restore(const QString &fileName)
122 {
123     const QFileInfo info(fileName);
124     if (!info.exists())
125     {
126         return false;
127     }
128 
129     QFile file(fileName);
130     if (!file.open(QIODevice::ReadOnly))
131     {
132         return false;
133     }
134     QDataStream stream(&file);
135     QList<QNetworkCookie> list;
136     stream >> list;
137     setAllCookies(removeExpired(list));
138     file.close();
139     return true;
140 }
141 
removeExpired(const QList<QNetworkCookie> & cookies)142 QList<QNetworkCookie> CookieJar::removeExpired(const QList<QNetworkCookie> &cookies)
143 {
144     QList<QNetworkCookie> updatedList;
145     foreach (const QNetworkCookie &cookie, cookies) {
146         if (cookie.expirationDate() > QDateTime::currentDateTimeUtc() && !cookie.isSessionCookie()) {
147             updatedList << cookie;
148         }
149     }
150     return updatedList;
151 }
152 
153 } // namespace OCC
154