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, "nextcloud.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 (const auto &cookie : list)
39         stream << cookie.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 = 0;
48     stream >> version;
49 
50     if (version != JAR_VERSION)
51         return stream;
52 
53     quint32 count = 0;
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 
75 CookieJar::~CookieJar() = default;
76 
setCookiesFromUrl(const QList<QNetworkCookie> & cookieList,const QUrl & url)77 bool CookieJar::setCookiesFromUrl(const QList<QNetworkCookie> &cookieList, const QUrl &url)
78 {
79     if (QNetworkCookieJar::setCookiesFromUrl(cookieList, url)) {
80         Q_EMIT newCookiesForUrl(cookieList, url);
81         return true;
82     }
83 
84     return false;
85 }
86 
cookiesForUrl(const QUrl & url) const87 QList<QNetworkCookie> CookieJar::cookiesForUrl(const QUrl &url) const
88 {
89     QList<QNetworkCookie> cookies = QNetworkCookieJar::cookiesForUrl(url);
90     qCDebug(lcCookieJar) << url << "requests:" << cookies;
91     return cookies;
92 }
93 
clearSessionCookies()94 void CookieJar::clearSessionCookies()
95 {
96     setAllCookies(removeExpired(allCookies()));
97 }
98 
save(const QString & fileName)99 bool CookieJar::save(const QString &fileName)
100 {
101     const QFileInfo info(fileName);
102     if (!info.dir().exists())
103     {
104         info.dir().mkpath(".");
105     }
106 
107     qCDebug(lcCookieJar) << fileName;
108     QFile file(fileName);
109     if (!file.open(QIODevice::WriteOnly))
110     {
111         return false;
112     }
113     QDataStream stream(&file);
114     stream << removeExpired(allCookies());
115     file.close();
116     return true;
117 }
118 
restore(const QString & fileName)119 bool CookieJar::restore(const QString &fileName)
120 {
121     const QFileInfo info(fileName);
122     if (!info.exists())
123     {
124         return false;
125     }
126 
127     QFile file(fileName);
128     if (!file.open(QIODevice::ReadOnly))
129     {
130         return false;
131     }
132     QDataStream stream(&file);
133     QList<QNetworkCookie> list;
134     stream >> list;
135     setAllCookies(removeExpired(list));
136     file.close();
137     return true;
138 }
139 
removeExpired(const QList<QNetworkCookie> & cookies)140 QList<QNetworkCookie> CookieJar::removeExpired(const QList<QNetworkCookie> &cookies)
141 {
142     QList<QNetworkCookie> updatedList;
143     foreach (const QNetworkCookie &cookie, cookies) {
144         if (cookie.expirationDate() > QDateTime::currentDateTimeUtc() && !cookie.isSessionCookie()) {
145             updatedList << cookie;
146         }
147     }
148     return updatedList;
149 }
150 
151 } // namespace OCC
152