summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTimothy Flynn <trflynn89@pm.me>2023-02-24 11:51:56 -0500
committerTim Flynn <trflynn89@pm.me>2023-02-24 15:50:42 -0500
commit87c4080d009d8f3d714a2f9ad4774696d933902d (patch)
tree0d5f5e47562afdc329fa072ed9418a375e593240
parent1858163d3ca39b538f847046d781422e5b6026a0 (diff)
downloadserenity-87c4080d009d8f3d714a2f9ad4774696d933902d.zip
Browser+LibWeb+WebContent: Store cookie expiry times in UTC
We are currently converting parsed expiry times to local time, whereas the RFC dictates we parse them as UTC. When expiring cookies, we must also use the current UTC time to compare against the cookies' expiry times.
-rw-r--r--Userland/Applications/Browser/CookieJar.cpp40
-rw-r--r--Userland/Applications/Browser/CookiesModel.cpp2
-rw-r--r--Userland/Applications/Browser/StorageWidget.cpp2
-rw-r--r--Userland/Libraries/LibWeb/Cookie/Cookie.cpp29
-rw-r--r--Userland/Libraries/LibWeb/Cookie/Cookie.h14
-rw-r--r--Userland/Libraries/LibWeb/Cookie/ParsedCookie.cpp26
-rw-r--r--Userland/Libraries/LibWeb/Cookie/ParsedCookie.h8
-rw-r--r--Userland/Services/WebContent/WebDriverConnection.cpp9
8 files changed, 83 insertions, 47 deletions
diff --git a/Userland/Applications/Browser/CookieJar.cpp b/Userland/Applications/Browser/CookieJar.cpp
index 2e39fce90d..76d987f8f8 100644
--- a/Userland/Applications/Browser/CookieJar.cpp
+++ b/Userland/Applications/Browser/CookieJar.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2021-2022, Tim Flynn <trflynn89@serenityos.org>
+ * Copyright (c) 2021-2023, Tim Flynn <trflynn89@serenityos.org>
* Copyright (c) 2022, the SerenityOS developers.
* Copyright (c) 2022, Tobias Christiansen <tobyase@serenityos.org>
*
@@ -11,6 +11,7 @@
#include <AK/IPv4Address.h>
#include <AK/StringBuilder.h>
#include <AK/StringView.h>
+#include <AK/Time.h>
#include <AK/URL.h>
#include <AK/Vector.h>
#include <LibCore/Promise.h>
@@ -140,9 +141,9 @@ void CookieJar::dump_cookies()
builder.appendff("{}{}{}\n", key_color, cookie.path, no_color);
builder.appendff("\t{}Value{} = {}\n", attribute_color, no_color, cookie.value);
- builder.appendff("\t{}CreationTime{} = {}\n", attribute_color, no_color, cookie.creation_time.to_deprecated_string());
- builder.appendff("\t{}LastAccessTime{} = {}\n", attribute_color, no_color, cookie.last_access_time.to_deprecated_string());
- builder.appendff("\t{}ExpiryTime{} = {}\n", attribute_color, no_color, cookie.expiry_time.to_deprecated_string());
+ builder.appendff("\t{}CreationTime{} = {}\n", attribute_color, no_color, cookie.creation_time_to_string());
+ builder.appendff("\t{}LastAccessTime{} = {}\n", attribute_color, no_color, cookie.last_access_time_to_string());
+ builder.appendff("\t{}ExpiryTime{} = {}\n", attribute_color, no_color, cookie.expiry_time_to_string());
builder.appendff("\t{}Secure{} = {:s}\n", attribute_color, no_color, cookie.secure);
builder.appendff("\t{}HttpOnly{} = {:s}\n", attribute_color, no_color, cookie.http_only);
builder.appendff("\t{}HostOnly{} = {:s}\n", attribute_color, no_color, cookie.host_only);
@@ -275,7 +276,7 @@ void CookieJar::store_cookie(Web::Cookie::ParsedCookie const& parsed_cookie, con
// 2. Create a new cookie with name cookie-name, value cookie-value. Set the creation-time and the last-access-time to the current date and time.
Web::Cookie::Cookie cookie { parsed_cookie.name, parsed_cookie.value, parsed_cookie.same_site_attribute };
- cookie.creation_time = Core::DateTime::now();
+ cookie.creation_time = Time::now_realtime();
cookie.last_access_time = cookie.creation_time;
if (parsed_cookie.expiry_time_from_max_age_attribute.has_value()) {
@@ -289,9 +290,9 @@ void CookieJar::store_cookie(Web::Cookie::ParsedCookie const& parsed_cookie, con
cookie.persistent = true;
cookie.expiry_time = parsed_cookie.expiry_time_from_expires_attribute.value();
} else {
- // Set the cookie's persistent-flag to false. Set the cookie's expiry-time to the latest representable gddate.
+ // Set the cookie's persistent-flag to false. Set the cookie's expiry-time to the latest representable date.
cookie.persistent = false;
- cookie.expiry_time = Core::DateTime::create(9999, 12, 31, 23, 59, 59);
+ cookie.expiry_time = Time::max();
}
// 4. If the cookie-attribute-list contains an attribute with an attribute-name of "Domain":
@@ -396,13 +397,13 @@ Vector<Web::Cookie::Cookie> CookieJar::get_matching_cookies(const URL& url, Depr
// - Cookies with longer paths are listed before cookies with shorter paths.
// - Among cookies that have equal-length path fields, cookies with earlier creation-times are listed before cookies with later creation-times.
auto cookie_path_length = cookie.path.length();
- auto cookie_creation_time = cookie.creation_time.timestamp();
+ auto cookie_creation_time = cookie.creation_time;
cookie_list.insert_before_matching(move(cookie), [cookie_path_length, cookie_creation_time](auto const& entry) {
if (cookie_path_length > entry.path.length()) {
return true;
} else if (cookie_path_length == entry.path.length()) {
- if (cookie_creation_time < entry.creation_time.timestamp())
+ if (cookie_creation_time < entry.creation_time)
return true;
}
return false;
@@ -410,7 +411,7 @@ Vector<Web::Cookie::Cookie> CookieJar::get_matching_cookies(const URL& url, Depr
});
// 3. Update the last-access-time of each cookie in the cookie-list to the current date and time.
- auto now = Core::DateTime::now();
+ auto now = Time::now_realtime();
for (auto& cookie : cookie_list) {
cookie.last_access_time = now;
@@ -450,8 +451,8 @@ static ErrorOr<Web::Cookie::Cookie> parse_cookie(ReadonlySpan<SQL::Value> row)
if (value.type() != SQL::SQLType::Integer)
return Error::from_string_view(name);
- auto time = value.to_int<time_t>().value();
- field = Core::DateTime::from_timestamp(time);
+ auto time = value.to_int<i64>().value();
+ field = Time::from_seconds(time);
return {};
};
@@ -492,9 +493,9 @@ void CookieJar::insert_cookie_into_database(Web::Cookie::Cookie const& cookie)
cookie.name,
cookie.value,
to_underlying(cookie.same_site),
- cookie.creation_time.timestamp(),
- cookie.last_access_time.timestamp(),
- cookie.expiry_time.timestamp(),
+ cookie.creation_time.to_seconds(),
+ cookie.last_access_time.to_seconds(),
+ cookie.expiry_time.to_seconds(),
cookie.domain,
cookie.path,
cookie.secure,
@@ -509,9 +510,9 @@ void CookieJar::update_cookie_in_database(Web::Cookie::Cookie const& cookie)
m_statements.update_cookie, {}, [this]() { purge_expired_cookies(); }, {},
cookie.value,
to_underlying(cookie.same_site),
- cookie.creation_time.timestamp(),
- cookie.last_access_time.timestamp(),
- cookie.expiry_time.timestamp(),
+ cookie.creation_time.to_seconds(),
+ cookie.last_access_time.to_seconds(),
+ cookie.expiry_time.to_seconds(),
cookie.secure,
cookie.http_only,
cookie.host_only,
@@ -581,7 +582,8 @@ void CookieJar::select_all_cookies_from_database(OnSelectAllCookiesResult on_res
void CookieJar::purge_expired_cookies()
{
- auto now = Core::DateTime::now().timestamp();
+ auto now = Time::now_realtime().to_seconds();
m_database.execute_statement(m_statements.expire_cookie, {}, {}, {}, now);
}
+
}
diff --git a/Userland/Applications/Browser/CookiesModel.cpp b/Userland/Applications/Browser/CookiesModel.cpp
index 50df78a243..2d16901bd5 100644
--- a/Userland/Applications/Browser/CookiesModel.cpp
+++ b/Userland/Applications/Browser/CookiesModel.cpp
@@ -80,7 +80,7 @@ GUI::Variant CookiesModel::data(GUI::ModelIndex const& index, GUI::ModelRole rol
case Column::Value:
return cookie.value;
case Column::ExpiryTime:
- return cookie.expiry_time.to_deprecated_string();
+ return cookie.expiry_time_to_string();
case Column::SameSite:
return Web::Cookie::same_site_to_string(cookie.same_site);
}
diff --git a/Userland/Applications/Browser/StorageWidget.cpp b/Userland/Applications/Browser/StorageWidget.cpp
index 4c7314fd87..9837b879cd 100644
--- a/Userland/Applications/Browser/StorageWidget.cpp
+++ b/Userland/Applications/Browser/StorageWidget.cpp
@@ -130,7 +130,7 @@ void StorageWidget::clear_session_storage_entries()
void StorageWidget::delete_cookie(Web::Cookie::Cookie cookie)
{
// Delete cookie by making its expiry time in the past.
- cookie.expiry_time = Core::DateTime::from_timestamp(0);
+ cookie.expiry_time = Time::from_seconds(0);
if (on_update_cookie)
on_update_cookie(move(cookie));
}
diff --git a/Userland/Libraries/LibWeb/Cookie/Cookie.cpp b/Userland/Libraries/LibWeb/Cookie/Cookie.cpp
index 229ca38090..bbef4fb5c6 100644
--- a/Userland/Libraries/LibWeb/Cookie/Cookie.cpp
+++ b/Userland/Libraries/LibWeb/Cookie/Cookie.cpp
@@ -1,15 +1,38 @@
/*
* Copyright (c) 2022, Tobias Christiansen <tobyase@serenityos.org>
+ * Copyright (c) 2023, Tim Flynn <trflynn89@serenityos.org>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#include "Cookie.h"
+#include <LibCore/DateTime.h>
#include <LibIPC/Decoder.h>
#include <LibIPC/Encoder.h>
namespace Web::Cookie {
+static DeprecatedString time_to_string(Time const& time)
+{
+ auto local_time = Core::DateTime::from_timestamp(time.to_seconds());
+ return local_time.to_deprecated_string("%Y-%m-%d %H:%M:%S %Z"sv);
+}
+
+DeprecatedString Cookie::creation_time_to_string() const
+{
+ return time_to_string(creation_time);
+}
+
+DeprecatedString Cookie::last_access_time_to_string() const
+{
+ return time_to_string(last_access_time);
+}
+
+DeprecatedString Cookie::expiry_time_to_string() const
+{
+ return time_to_string(expiry_time);
+}
+
StringView same_site_to_string(SameSite same_site)
{
switch (same_site) {
@@ -64,11 +87,11 @@ ErrorOr<Web::Cookie::Cookie> IPC::decode(Decoder& decoder)
auto value = TRY(decoder.decode<DeprecatedString>());
auto domain = TRY(decoder.decode<DeprecatedString>());
auto path = TRY(decoder.decode<DeprecatedString>());
- auto creation_time = TRY(decoder.decode<Core::DateTime>());
- auto expiry_time = TRY(decoder.decode<Core::DateTime>());
+ auto creation_time = TRY(decoder.decode<Time>());
+ auto expiry_time = TRY(decoder.decode<Time>());
auto host_only = TRY(decoder.decode<bool>());
auto http_only = TRY(decoder.decode<bool>());
- auto last_access_time = TRY(decoder.decode<Core::DateTime>());
+ auto last_access_time = TRY(decoder.decode<Time>());
auto persistent = TRY(decoder.decode<bool>());
auto secure = TRY(decoder.decode<bool>());
auto same_site = TRY(decoder.decode<Web::Cookie::SameSite>());
diff --git a/Userland/Libraries/LibWeb/Cookie/Cookie.h b/Userland/Libraries/LibWeb/Cookie/Cookie.h
index c3b4c9768c..e54d168621 100644
--- a/Userland/Libraries/LibWeb/Cookie/Cookie.h
+++ b/Userland/Libraries/LibWeb/Cookie/Cookie.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2021, Tim Flynn <trflynn89@serenityos.org>
+ * Copyright (c) 2021-2023, Tim Flynn <trflynn89@serenityos.org>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
@@ -7,7 +7,7 @@
#pragma once
#include <AK/DeprecatedString.h>
-#include <LibCore/DateTime.h>
+#include <AK/Time.h>
#include <LibIPC/Forward.h>
namespace Web::Cookie {
@@ -25,12 +25,16 @@ enum class Source {
};
struct Cookie {
+ DeprecatedString creation_time_to_string() const;
+ DeprecatedString last_access_time_to_string() const;
+ DeprecatedString expiry_time_to_string() const;
+
DeprecatedString name;
DeprecatedString value;
SameSite same_site;
- Core::DateTime creation_time {};
- Core::DateTime last_access_time {};
- Core::DateTime expiry_time {};
+ Time creation_time {};
+ Time last_access_time {};
+ Time expiry_time {};
DeprecatedString domain {};
DeprecatedString path {};
bool secure { false };
diff --git a/Userland/Libraries/LibWeb/Cookie/ParsedCookie.cpp b/Userland/Libraries/LibWeb/Cookie/ParsedCookie.cpp
index e04870f1bb..0d6102b114 100644
--- a/Userland/Libraries/LibWeb/Cookie/ParsedCookie.cpp
+++ b/Userland/Libraries/LibWeb/Cookie/ParsedCookie.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2021, Tim Flynn <trflynn89@serenityos.org>
+ * Copyright (c) 2021-2023, Tim Flynn <trflynn89@serenityos.org>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
@@ -8,6 +8,7 @@
#include <AK/DateConstants.h>
#include <AK/Function.h>
#include <AK/StdLibExtras.h>
+#include <AK/Time.h>
#include <AK/Vector.h>
#include <LibIPC/Decoder.h>
#include <LibIPC/Encoder.h>
@@ -26,7 +27,7 @@ static void on_path_attribute(ParsedCookie& parsed_cookie, StringView attribute_
static void on_secure_attribute(ParsedCookie& parsed_cookie);
static void on_http_only_attribute(ParsedCookie& parsed_cookie);
static void on_same_site_attribute(ParsedCookie& parsed_cookie, StringView attribute_value);
-static Optional<Core::DateTime> parse_date_time(StringView date_string);
+static Optional<Time> parse_date_time(StringView date_string);
Optional<ParsedCookie> parse_cookie(DeprecatedString const& cookie_string)
{
@@ -153,7 +154,7 @@ void on_expires_attribute(ParsedCookie& parsed_cookie, StringView attribute_valu
{
// https://tools.ietf.org/html/rfc6265#section-5.2.1
if (auto expiry_time = parse_date_time(attribute_value); expiry_time.has_value())
- parsed_cookie.expiry_time_from_expires_attribute = move(*expiry_time);
+ parsed_cookie.expiry_time_from_expires_attribute = expiry_time.release_value();
}
void on_max_age_attribute(ParsedCookie& parsed_cookie, StringView attribute_value)
@@ -168,11 +169,10 @@ void on_max_age_attribute(ParsedCookie& parsed_cookie, StringView attribute_valu
if (auto delta_seconds = attribute_value.to_int(); delta_seconds.has_value()) {
if (*delta_seconds <= 0) {
// If delta-seconds is less than or equal to zero (0), let expiry-time be the earliest representable date and time.
- parsed_cookie.expiry_time_from_max_age_attribute = Core::DateTime::from_timestamp(0);
+ parsed_cookie.expiry_time_from_max_age_attribute = Time::min();
} else {
// Otherwise, let the expiry-time be the current date and time plus delta-seconds seconds.
- time_t now = Core::DateTime::now().timestamp();
- parsed_cookie.expiry_time_from_max_age_attribute = Core::DateTime::from_timestamp(now + *delta_seconds);
+ parsed_cookie.expiry_time_from_max_age_attribute = Time::now_realtime() + Time::from_seconds(*delta_seconds);
}
}
}
@@ -236,7 +236,7 @@ void on_same_site_attribute(ParsedCookie& parsed_cookie, StringView attribute_va
parsed_cookie.same_site_attribute = same_site_from_string(attribute_value);
}
-Optional<Core::DateTime> parse_date_time(StringView date_string)
+Optional<Time> parse_date_time(StringView date_string)
{
// https://tools.ietf.org/html/rfc6265#section-5.1.1
unsigned hour = 0;
@@ -341,8 +341,14 @@ Optional<Core::DateTime> parse_date_time(StringView date_string)
if (second > 59)
return {};
+ // 6. Let the parsed-cookie-date be the date whose day-of-month, month, year, hour, minute, and second (in UTC) are the
+ // day-of-month-value, the month-value, the year-value, the hour-value, the minute-value, and the second-value, respectively.
+ // If no such date exists, abort these steps and fail to parse the cookie-date.
// FIXME: Fail on dates that do not exist.
- return Core::DateTime::create(year, month, day_of_month, hour, minute, second);
+ auto parsed_cookie_date = Time::from_timestamp(year, month, day_of_month, hour, minute, second, 0);
+
+ // 7. Return the parsed-cookie-date as the result of this algorithm.
+ return parsed_cookie_date;
}
}
@@ -368,8 +374,8 @@ ErrorOr<Web::Cookie::ParsedCookie> IPC::decode(Decoder& decoder)
{
auto name = TRY(decoder.decode<DeprecatedString>());
auto value = TRY(decoder.decode<DeprecatedString>());
- auto expiry_time_from_expires_attribute = TRY(decoder.decode<Optional<Core::DateTime>>());
- auto expiry_time_from_max_age_attribute = TRY(decoder.decode<Optional<Core::DateTime>>());
+ auto expiry_time_from_expires_attribute = TRY(decoder.decode<Optional<Time>>());
+ auto expiry_time_from_max_age_attribute = TRY(decoder.decode<Optional<Time>>());
auto domain = TRY(decoder.decode<Optional<DeprecatedString>>());
auto path = TRY(decoder.decode<Optional<DeprecatedString>>());
auto secure_attribute_present = TRY(decoder.decode<bool>());
diff --git a/Userland/Libraries/LibWeb/Cookie/ParsedCookie.h b/Userland/Libraries/LibWeb/Cookie/ParsedCookie.h
index 07cc36b292..5779f8d5ee 100644
--- a/Userland/Libraries/LibWeb/Cookie/ParsedCookie.h
+++ b/Userland/Libraries/LibWeb/Cookie/ParsedCookie.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2021, Tim Flynn <trflynn89@serenityos.org>
+ * Copyright (c) 2021-2023, Tim Flynn <trflynn89@serenityos.org>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
@@ -8,7 +8,7 @@
#include <AK/DeprecatedString.h>
#include <AK/Optional.h>
-#include <LibCore/DateTime.h>
+#include <AK/Time.h>
#include <LibIPC/Forward.h>
#include <LibWeb/Cookie/Cookie.h>
@@ -18,8 +18,8 @@ struct ParsedCookie {
DeprecatedString name;
DeprecatedString value;
SameSite same_site_attribute { SameSite::Default };
- Optional<Core::DateTime> expiry_time_from_expires_attribute {};
- Optional<Core::DateTime> expiry_time_from_max_age_attribute {};
+ Optional<Time> expiry_time_from_expires_attribute {};
+ Optional<Time> expiry_time_from_max_age_attribute {};
Optional<DeprecatedString> domain {};
Optional<DeprecatedString> path {};
bool secure_attribute_present { false };
diff --git a/Userland/Services/WebContent/WebDriverConnection.cpp b/Userland/Services/WebContent/WebDriverConnection.cpp
index 0361199cad..bc9fcc9514 100644
--- a/Userland/Services/WebContent/WebDriverConnection.cpp
+++ b/Userland/Services/WebContent/WebDriverConnection.cpp
@@ -3,13 +3,14 @@
* Copyright (c) 2022-2023, Sam Atkins <atkinssj@serenityos.org>
* Copyright (c) 2022, Tobias Christiansen <tobyase@serenityos.org>
* Copyright (c) 2022, Linus Groh <linusg@serenityos.org>
- * Copyright (c) 2022, Tim Flynn <trflynn89@serenityos.org>
+ * Copyright (c) 2022-2023, Tim Flynn <trflynn89@serenityos.org>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <AK/JsonObject.h>
#include <AK/JsonValue.h>
+#include <AK/Time.h>
#include <AK/Vector.h>
#include <LibJS/Runtime/JSONObject.h>
#include <LibJS/Runtime/Value.h>
@@ -54,7 +55,7 @@ static JsonValue serialize_cookie(Web::Cookie::Cookie const& cookie)
serialized_cookie.set("domain"sv, cookie.domain);
serialized_cookie.set("secure"sv, cookie.secure);
serialized_cookie.set("httpOnly"sv, cookie.http_only);
- serialized_cookie.set("expiry"sv, cookie.expiry_time.timestamp());
+ serialized_cookie.set("expiry"sv, cookie.expiry_time.to_seconds());
serialized_cookie.set("sameSite"sv, Web::Cookie::same_site_to_string(cookie.same_site));
return serialized_cookie;
@@ -1593,7 +1594,7 @@ Messages::WebDriverClient::AddCookieResponse WebDriverConnection::add_cookie(Jso
if (data.has("expiry"sv)) {
// NOTE: less than 0 or greater than safe integer are handled by the JSON parser
auto expiry = TRY(get_property<u32>(data, "expiry"sv));
- cookie.expiry_time_from_expires_attribute = Core::DateTime::from_timestamp(expiry);
+ cookie.expiry_time_from_expires_attribute = Time::from_seconds(expiry);
}
// Cookie same site
@@ -1985,7 +1986,7 @@ void WebDriverConnection::delete_cookies(Optional<StringView> const& name)
// -> name is equal to cookie name
if (!name.has_value() || name.value() == cookie.name) {
// Set the cookie expiry time to a Unix timestamp in the past.
- cookie.expiry_time = Core::DateTime::from_timestamp(0);
+ cookie.expiry_time = Time::from_seconds(0);
m_page_client.page_did_update_cookie(move(cookie));
}
// -> Otherwise