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