Title: [253489] trunk
Revision
253489
Author
[email protected]
Date
2019-12-13 11:18:37 -0800 (Fri, 13 Dec 2019)

Log Message

IsLoggedIn: Abstract data type for IsLoggedIn state
https://bugs.webkit.org/show_bug.cgi?id=205041
<rdar://problem/56723904>

Reviewed by Chris Dumez.

Source/WebCore:

New API tests added.

* Sources.txt:
* WebCore.xcodeproj/project.pbxproj:
* page/LoggedInStatus.cpp: Added.
(WebCore::LoggedInStatus::create):
(WebCore::LoggedInStatus::LoggedInStatus):
(WebCore::LoggedInStatus::setTimeToLive):
(WebCore::LoggedInStatus::hasExpired const):
(WebCore::LoggedInStatus::expiry const):
* page/LoggedInStatus.h: Added.
(WebCore::LoggedInStatus::registrableDomain const):
(WebCore::LoggedInStatus::username const):
(WebCore::LoggedInStatus::credentialTokenType const):
(WebCore::LoggedInStatus::authenticationType const):
(WebCore::LoggedInStatus::loggedInTime const):

Tools:

* TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj:
* TestWebKitAPI/Tests/WebCore/LoggedInStatus.cpp: Added.
(TestWebKitAPI::TEST):

Modified Paths

Added Paths

Diff

Modified: trunk/Source/WebCore/ChangeLog (253488 => 253489)


--- trunk/Source/WebCore/ChangeLog	2019-12-13 19:07:51 UTC (rev 253488)
+++ trunk/Source/WebCore/ChangeLog	2019-12-13 19:18:37 UTC (rev 253489)
@@ -1,3 +1,28 @@
+2019-12-13  John Wilander  <[email protected]>
+
+        IsLoggedIn: Abstract data type for IsLoggedIn state
+        https://bugs.webkit.org/show_bug.cgi?id=205041
+        <rdar://problem/56723904>
+
+        Reviewed by Chris Dumez.
+
+        New API tests added.
+
+        * Sources.txt:
+        * WebCore.xcodeproj/project.pbxproj:
+        * page/LoggedInStatus.cpp: Added.
+        (WebCore::LoggedInStatus::create):
+        (WebCore::LoggedInStatus::LoggedInStatus):
+        (WebCore::LoggedInStatus::setTimeToLive):
+        (WebCore::LoggedInStatus::hasExpired const):
+        (WebCore::LoggedInStatus::expiry const):
+        * page/LoggedInStatus.h: Added.
+        (WebCore::LoggedInStatus::registrableDomain const):
+        (WebCore::LoggedInStatus::username const):
+        (WebCore::LoggedInStatus::credentialTokenType const):
+        (WebCore::LoggedInStatus::authenticationType const):
+        (WebCore::LoggedInStatus::loggedInTime const):
+
 2019-12-13  Per Arne Vollan  <[email protected]>
 
         [iOS] Deny mach lookup access to "*.apple-extension-service" in the WebContent process

Modified: trunk/Source/WebCore/Sources.txt (253488 => 253489)


--- trunk/Source/WebCore/Sources.txt	2019-12-13 19:07:51 UTC (rev 253488)
+++ trunk/Source/WebCore/Sources.txt	2019-12-13 19:18:37 UTC (rev 253489)
@@ -1608,6 +1608,7 @@
 page/History.cpp
 page/IntersectionObserver.cpp
 page/IntersectionObserverEntry.cpp
+page/LoggedInStatus.cpp
 page/Location.cpp
 page/MemoryRelease.cpp
 page/MouseEventWithHitTestResults.cpp

Modified: trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj (253488 => 253489)


--- trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj	2019-12-13 19:07:51 UTC (rev 253488)
+++ trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj	2019-12-13 19:18:37 UTC (rev 253489)
@@ -1991,6 +1991,7 @@
 		6B0A07F221FA4B5C00D57391 /* AdClickAttribution.h in Headers */ = {isa = PBXBuildFile; fileRef = 6B0A07F021FA4B5C00D57391 /* AdClickAttribution.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		6B1F48112298A37E00DE8B82 /* CrossSiteNavigationDataTransfer.h in Headers */ = {isa = PBXBuildFile; fileRef = 6B1F480F22989EC400DE8B82 /* CrossSiteNavigationDataTransfer.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		6B3480940EEF50D400AC1B41 /* NativeImage.h in Headers */ = {isa = PBXBuildFile; fileRef = 6B3480920EEF50D400AC1B41 /* NativeImage.h */; settings = {ATTRIBUTES = (Private, ); }; };
+		6B4D412D23983F88002494C2 /* LoggedInStatus.h in Headers */ = {isa = PBXBuildFile; fileRef = 6B4D412B23983F88002494C2 /* LoggedInStatus.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		6B4E8613221B713F0022F389 /* RegistrableDomain.h in Headers */ = {isa = PBXBuildFile; fileRef = 6B4E8612221B713F0022F389 /* RegistrableDomain.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		6B507A24234BF34100BE7C62 /* NavigatorIsLoggedIn.h in Headers */ = {isa = PBXBuildFile; fileRef = 6B507A21234BF34100BE7C62 /* NavigatorIsLoggedIn.h */; };
 		6B693A2E1C51A82E00B03BEF /* ResourceLoadObserver.h in Headers */ = {isa = PBXBuildFile; fileRef = 6B693A2D1C51A82E00B03BEF /* ResourceLoadObserver.h */; settings = {ATTRIBUTES = (Private, ); }; };
@@ -9210,6 +9211,8 @@
 		6B0A07F121FA4B5C00D57391 /* AdClickAttribution.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = AdClickAttribution.cpp; sourceTree = "<group>"; };
 		6B1F480F22989EC400DE8B82 /* CrossSiteNavigationDataTransfer.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CrossSiteNavigationDataTransfer.h; sourceTree = "<group>"; };
 		6B3480920EEF50D400AC1B41 /* NativeImage.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = NativeImage.h; sourceTree = "<group>"; };
+		6B4D412B23983F88002494C2 /* LoggedInStatus.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = LoggedInStatus.h; sourceTree = "<group>"; };
+		6B4D412C23983F88002494C2 /* LoggedInStatus.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = LoggedInStatus.cpp; sourceTree = "<group>"; };
 		6B4E8612221B713F0022F389 /* RegistrableDomain.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RegistrableDomain.h; sourceTree = "<group>"; };
 		6B507A21234BF34100BE7C62 /* NavigatorIsLoggedIn.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = NavigatorIsLoggedIn.h; sourceTree = "<group>"; };
 		6B507A22234BF34100BE7C62 /* NavigatorIsLoggedIn.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = NavigatorIsLoggedIn.cpp; sourceTree = "<group>"; };
@@ -20672,6 +20675,8 @@
 				BCE1C41A0D982980003B02F2 /* Location.cpp */,
 				BCE1C4190D982980003B02F2 /* Location.h */,
 				BCE1C4220D9829F2003B02F2 /* Location.idl */,
+				6B4D412C23983F88002494C2 /* LoggedInStatus.cpp */,
+				6B4D412B23983F88002494C2 /* LoggedInStatus.h */,
 				931BCC601124DFCB00BE70DD /* MediaCanStartListener.h */,
 				52E2CAFB19FF0207001EEB4F /* MediaProducer.h */,
 				413E00771DB0E4DE002341D2 /* MemoryRelease.cpp */,
@@ -31333,6 +31338,7 @@
 				A516E8B7136E04DB0076C3C0 /* LocalizedDateCache.h in Headers */,
 				935207BE09BD410A00F2038D /* LocalizedStrings.h in Headers */,
 				BCE1C41B0D982980003B02F2 /* Location.h in Headers */,
+				6B4D412D23983F88002494C2 /* LoggedInStatus.h in Headers */,
 				A8239E0109B3CF8A00B60641 /* Logging.h in Headers */,
 				9BA273F4172206BB0097CE47 /* LogicalSelectionOffsetCaches.h in Headers */,
 				0FDCD7F31D47E655009F08BC /* LogInitialization.h in Headers */,

Added: trunk/Source/WebCore/page/LoggedInStatus.cpp (0 => 253489)


--- trunk/Source/WebCore/page/LoggedInStatus.cpp	                        (rev 0)
+++ trunk/Source/WebCore/page/LoggedInStatus.cpp	2019-12-13 19:18:37 UTC (rev 253489)
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2019 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "LoggedInStatus.h"
+
+#include <wtf/IsoMallocInlines.h>
+#include <wtf/text/StringCommon.h>
+
+namespace WebCore {
+
+using CodeUnitMatchFunction = bool (*)(UChar);
+
+WTF_MAKE_ISO_ALLOCATED_IMPL(LoggedInStatus);
+
+ExceptionOr<UniqueRef<LoggedInStatus>> LoggedInStatus::create(const RegistrableDomain& domain, const String& username, CredentialTokenType tokenType, AuthenticationType authType)
+{
+    return create(domain, username, tokenType, authType, authType == AuthenticationType::Unmanaged ? TimeToLiveShort : TimeToLiveLong);
+}
+
+ExceptionOr<UniqueRef<LoggedInStatus>> LoggedInStatus::create(const RegistrableDomain& domain, const String& username, CredentialTokenType tokenType, AuthenticationType authType, Seconds timeToLive)
+{
+    if (domain.isEmpty())
+        return Exception { SecurityError, "IsLoggedIn status can only be set for origins with a registrable domain." };
+
+    if (username.isEmpty())
+        return Exception { SyntaxError, "IsLoggedIn requires a non-empty username." };
+
+    unsigned length = username.length();
+    if (length > UsernameMaxLength)
+        return Exception { SyntaxError, makeString("IsLoggedIn usernames cannot be longer than ", UsernameMaxLength) };
+
+    auto spaceOrNewline = username.find([](UChar ch) {
+        return isSpaceOrNewline(ch);
+    });
+    if (spaceOrNewline != notFound)
+        return Exception { InvalidCharacterError, "IsLoggedIn usernames cannot contain whitespace or newlines." };
+
+    return makeUniqueRef<LoggedInStatus>(*new LoggedInStatus(domain, username, tokenType, authType, timeToLive));
+}
+
+LoggedInStatus::LoggedInStatus(const RegistrableDomain& domain, const String& username, CredentialTokenType tokenType, AuthenticationType authType, Seconds timeToLive)
+    : m_domain { domain }
+    , m_username { username }
+    , m_tokenType { tokenType }
+    , m_authType { authType }
+    , m_loggedInTime { WallTime::now() }
+{
+    setTimeToLive(timeToLive);
+}
+
+void LoggedInStatus::setTimeToLive(Seconds timeToLive)
+{
+    m_timeToLive = std::min(timeToLive, m_authType == AuthenticationType::Unmanaged ? TimeToLiveShort : TimeToLiveLong);
+}
+
+bool LoggedInStatus::hasExpired() const
+{
+    ASSERT(!m_domain.isEmpty() && !m_username.isEmpty());
+    return WallTime::now() > m_loggedInTime + m_timeToLive;
+}
+
+WallTime LoggedInStatus::expiry() const
+{
+    return WallTime::now() + m_timeToLive;
+}
+
+}

Added: trunk/Source/WebCore/page/LoggedInStatus.h (0 => 253489)


--- trunk/Source/WebCore/page/LoggedInStatus.h	                        (rev 0)
+++ trunk/Source/WebCore/page/LoggedInStatus.h	2019-12-13 19:18:37 UTC (rev 253489)
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2019 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#include "ExceptionOr.h"
+#include "RegistrableDomain.h"
+#include <wtf/EnumTraits.h>
+#include <wtf/IsoMalloc.h>
+#include <wtf/UniqueRef.h>
+#include <wtf/WallTime.h>
+#include <wtf/text/WTFString.h>
+
+namespace WebCore {
+
+class LoggedInStatus {
+    WTF_MAKE_ISO_ALLOCATED_EXPORT(LoggedInStatus, WEBCORE_EXPORT);
+public:
+    static constexpr uint32_t UsernameMaxLength = 64;
+    static constexpr Seconds TimeToLiveShort { 24_h * 7 };
+    static constexpr Seconds TimeToLiveLong { 24_h * 90 };
+
+    enum class CredentialTokenType : bool { LegacyCookie, HTTPStateToken };
+    enum class AuthenticationType : uint8_t { WebAuthn, PasswordManager, Unmanaged };
+
+    WEBCORE_EXPORT static ExceptionOr<UniqueRef<LoggedInStatus>> create(const RegistrableDomain&, const String& username, CredentialTokenType, AuthenticationType);
+    WEBCORE_EXPORT static ExceptionOr<UniqueRef<LoggedInStatus>> create(const RegistrableDomain&, const String& username, CredentialTokenType, AuthenticationType, Seconds timeToLive);
+
+    WEBCORE_EXPORT void setTimeToLive(Seconds);
+    WEBCORE_EXPORT bool hasExpired() const;
+    WEBCORE_EXPORT WallTime expiry() const;
+
+    const RegistrableDomain& registrableDomain() const { return m_domain; }
+    const String& username() const { return m_username; }
+    CredentialTokenType credentialTokenType() const { return m_tokenType; }
+    AuthenticationType authenticationType() const { return m_authType; }
+    WallTime loggedInTime() const { return m_loggedInTime; }
+
+private:
+    LoggedInStatus(const RegistrableDomain&, const String& username, CredentialTokenType, AuthenticationType, Seconds timeToLive);
+
+    RegistrableDomain m_domain;
+    String m_username;
+    CredentialTokenType m_tokenType;
+    AuthenticationType m_authType;
+    WallTime m_loggedInTime;
+    Seconds m_timeToLive;
+};
+
+} // namespace WebCore
+
+namespace WTF {
+
+template<> struct EnumTraits<WebCore::LoggedInStatus::AuthenticationType> {
+    using values = EnumValues<
+        WebCore::LoggedInStatus::AuthenticationType,
+        WebCore::LoggedInStatus::AuthenticationType::WebAuthn,
+        WebCore::LoggedInStatus::AuthenticationType::PasswordManager,
+        WebCore::LoggedInStatus::AuthenticationType::Unmanaged
+    >;
+};
+
+} // namespace WTF

Modified: trunk/Tools/ChangeLog (253488 => 253489)


--- trunk/Tools/ChangeLog	2019-12-13 19:07:51 UTC (rev 253488)
+++ trunk/Tools/ChangeLog	2019-12-13 19:18:37 UTC (rev 253489)
@@ -1,3 +1,15 @@
+2019-12-13  John Wilander  <[email protected]>
+
+        IsLoggedIn: Abstract data type for IsLoggedIn state
+        https://bugs.webkit.org/show_bug.cgi?id=205041
+        <rdar://problem/56723904>
+
+        Reviewed by Chris Dumez.
+
+        * TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj:
+        * TestWebKitAPI/Tests/WebCore/LoggedInStatus.cpp: Added.
+        (TestWebKitAPI::TEST):
+
 2019-12-13  Wenson Hsieh  <[email protected]>
 
         [Clipboard API] Sanitize HTML and image data written using clipboard.write

Modified: trunk/Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj (253488 => 253489)


--- trunk/Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj	2019-12-13 19:07:51 UTC (rev 253488)
+++ trunk/Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj	2019-12-13 19:18:37 UTC (rev 253489)
@@ -441,6 +441,7 @@
 		6B306106218A372900F5A802 /* ClosingWebView.mm in Sources */ = {isa = PBXBuildFile; fileRef = 6B306105218A372900F5A802 /* ClosingWebView.mm */; };
 		6B4E861C2220A5520022F389 /* RegistrableDomain.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 6B4E861B2220A5520022F389 /* RegistrableDomain.cpp */; };
 		6B9ABE122086952F00D75DE6 /* HTTPParsers.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 6B9ABE112086952F00D75DE6 /* HTTPParsers.cpp */; };
+		6BF4A683239ED4CD00E2F45B /* LoggedInStatus.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 6BF4A682239ED4CD00E2F45B /* LoggedInStatus.cpp */; };
 		6BFD294C1D5E6C1D008EC968 /* HashCountedSet.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7A38D7E51C752D5F004F157D /* HashCountedSet.cpp */; };
 		725C3EF322058A5B007C36FC /* AdditionalSupportedImageTypes.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = 725C3EF2220584BA007C36FC /* AdditionalSupportedImageTypes.html */; };
 		7283A9D022FA754900B21C7D /* img-with-rotated-image.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = 7283A9CE22FA6BBE00B21C7D /* img-with-rotated-image.html */; };
@@ -2008,6 +2009,7 @@
 		6B306105218A372900F5A802 /* ClosingWebView.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = ClosingWebView.mm; sourceTree = "<group>"; };
 		6B4E861B2220A5520022F389 /* RegistrableDomain.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = RegistrableDomain.cpp; sourceTree = "<group>"; };
 		6B9ABE112086952F00D75DE6 /* HTTPParsers.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = HTTPParsers.cpp; sourceTree = "<group>"; };
+		6BF4A682239ED4CD00E2F45B /* LoggedInStatus.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = LoggedInStatus.cpp; sourceTree = "<group>"; };
 		725C3EF2220584BA007C36FC /* AdditionalSupportedImageTypes.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = AdditionalSupportedImageTypes.html; sourceTree = "<group>"; };
 		7283A9CE22FA6BBE00B21C7D /* img-with-rotated-image.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = "img-with-rotated-image.html"; sourceTree = "<group>"; };
 		7283A9D122FB1D9700B21C7D /* exif-orientation-8-llo.jpg */ = {isa = PBXFileReference; lastKnownFileType = image.jpeg; path = "exif-orientation-8-llo.jpg"; sourceTree = "<group>"; };
@@ -3114,6 +3116,7 @@
 				7A909A751D877475007E10F8 /* IntSize.cpp */,
 				CD5FF4962162E27E004BD86F /* ISOBox.cpp */,
 				14464012167A8305000BD218 /* LayoutUnit.cpp */,
+				6BF4A682239ED4CD00E2F45B /* LoggedInStatus.cpp */,
 				076E507E1F45031E006E9F5A /* Logging.cpp */,
 				CE1866471F72E8F100A0CAB6 /* MarkedText.cpp */,
 				A5B149DD1F5A19DC00C6DAFF /* MIMETypeRegistry.cpp */,
@@ -4731,6 +4734,7 @@
 				46C519DA1D355AB200DAA51A /* LocalStorageNullEntries.mm in Sources */,
 				8C10AF99206467A90018FD90 /* LocalStoragePersistence.mm in Sources */,
 				7A6A2C701DCCFA8C00C0D085 /* LocalStorageQuirkTest.mm in Sources */,
+				6BF4A683239ED4CD00E2F45B /* LoggedInStatus.cpp in Sources */,
 				076E507F1F4513D6006E9F5A /* Logging.cpp in Sources */,
 				CE1866491F72E8F100A0CAB6 /* MarkedText.cpp in Sources */,
 				07CC7DFE2266330900E39181 /* MediaBufferingPolicy.mm in Sources */,

Added: trunk/Tools/TestWebKitAPI/Tests/WebCore/LoggedInStatus.cpp (0 => 253489)


--- trunk/Tools/TestWebKitAPI/Tests/WebCore/LoggedInStatus.cpp	                        (rev 0)
+++ trunk/Tools/TestWebKitAPI/Tests/WebCore/LoggedInStatus.cpp	2019-12-13 19:18:37 UTC (rev 253489)
@@ -0,0 +1,197 @@
+/*
+ * Copyright (C) 2019 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#include <WebCore/LoggedInStatus.h>
+#include <WebCore/RegistrableDomain.h>
+#include <wtf/Seconds.h>
+#include <wtf/text/StringBuilder.h>
+
+using namespace WebCore;
+
+namespace TestWebKitAPI {
+
+// Positive test cases.
+
+TEST(LoggedInStatus, DefaultExpiryWebAuthn)
+{
+    RegistrableDomain loginDomain { URL { { }, "https://login.example.com"_s } };
+
+    auto loggedInResult = LoggedInStatus::create(loginDomain, "admin"_s, LoggedInStatus::CredentialTokenType::HTTPStateToken, LoggedInStatus::AuthenticationType::WebAuthn);
+    auto& loggedIn = loggedInResult.releaseReturnValue().get();
+    auto now = WallTime::now();
+    ASSERT_EQ(loggedIn.registrableDomain().string(), "example.com"_s);
+    ASSERT_EQ(loggedIn.username(), "admin"_s);
+    ASSERT_EQ(loggedIn.credentialTokenType(), LoggedInStatus::CredentialTokenType::HTTPStateToken);
+    ASSERT_EQ(loggedIn.authenticationType(), LoggedInStatus::AuthenticationType::WebAuthn);
+    ASSERT_TRUE(loggedIn.loggedInTime() < now + 60_s);
+    ASSERT_TRUE(loggedIn.loggedInTime() > now - 60_s);
+    ASSERT_TRUE(loggedIn.expiry() < now + LoggedInStatus::TimeToLiveLong + 60_s);
+    ASSERT_TRUE(loggedIn.expiry() > now + LoggedInStatus::TimeToLiveLong - 60_s);
+    ASSERT_FALSE(loggedIn.hasExpired());
+}
+
+TEST(LoggedInStatus, DefaultExpiryPasswordManager)
+{
+    RegistrableDomain loginDomain { URL { { }, "https://login.example.com"_s } };
+
+    auto loggedInResult = LoggedInStatus::create(loginDomain, "admin"_s, LoggedInStatus::CredentialTokenType::HTTPStateToken, LoggedInStatus::AuthenticationType::PasswordManager);
+    auto& loggedIn = loggedInResult.releaseReturnValue().get();
+    auto now = WallTime::now();
+    ASSERT_EQ(loggedIn.authenticationType(), LoggedInStatus::AuthenticationType::PasswordManager);
+    ASSERT_TRUE(loggedIn.expiry() < now + LoggedInStatus::TimeToLiveLong + 60_s);
+    ASSERT_TRUE(loggedIn.expiry() > now + LoggedInStatus::TimeToLiveLong - 60_s);
+    ASSERT_FALSE(loggedIn.hasExpired());
+}
+
+TEST(LoggedInStatus, DefaultExpiryUnmanaged)
+{
+    RegistrableDomain loginDomain { URL { { }, "https://login.example.com"_s } };
+
+    auto loggedInResult = LoggedInStatus::create(loginDomain, "admin"_s, LoggedInStatus::CredentialTokenType::HTTPStateToken, LoggedInStatus::AuthenticationType::Unmanaged);
+    auto& loggedIn = loggedInResult.releaseReturnValue().get();
+    auto now = WallTime::now();
+    ASSERT_EQ(loggedIn.authenticationType(), LoggedInStatus::AuthenticationType::Unmanaged);
+    ASSERT_TRUE(loggedIn.expiry() < now + LoggedInStatus::TimeToLiveShort + 60_s);
+    ASSERT_TRUE(loggedIn.expiry() > now + LoggedInStatus::TimeToLiveShort - 60_s);
+    ASSERT_FALSE(loggedIn.hasExpired());
+}
+
+TEST(LoggedInStatus, CustomExpiryBelowLong)
+{
+    RegistrableDomain loginDomain { URL { { }, "https://login.example.com"_s } };
+
+    auto customExpiry = LoggedInStatus::TimeToLiveLong - 48_h;
+    auto loggedInResult = LoggedInStatus::create(loginDomain, "admin"_s, LoggedInStatus::CredentialTokenType::HTTPStateToken, LoggedInStatus::AuthenticationType::WebAuthn, customExpiry);
+    auto& loggedIn = loggedInResult.releaseReturnValue().get();
+    auto now = WallTime::now();
+    ASSERT_EQ(loggedIn.authenticationType(), LoggedInStatus::AuthenticationType::WebAuthn);
+    ASSERT_TRUE(loggedIn.expiry() < now + customExpiry + 60_s);
+    ASSERT_TRUE(loggedIn.expiry() > now + customExpiry - 60_s);
+    ASSERT_FALSE(loggedIn.hasExpired());
+}
+
+TEST(LoggedInStatus, CustomExpiryBelowShort)
+{
+    RegistrableDomain loginDomain { URL { { }, "https://login.example.com"_s } };
+
+    auto customExpiry = LoggedInStatus::TimeToLiveShort - 48_h;
+    auto loggedInResult = LoggedInStatus::create(loginDomain, "admin"_s, LoggedInStatus::CredentialTokenType::HTTPStateToken, LoggedInStatus::AuthenticationType::PasswordManager, customExpiry);
+    auto& loggedIn = loggedInResult.releaseReturnValue().get();
+    auto now = WallTime::now();
+    ASSERT_EQ(loggedIn.authenticationType(), LoggedInStatus::AuthenticationType::PasswordManager);
+    ASSERT_TRUE(loggedIn.expiry() < now + customExpiry + 60_s);
+    ASSERT_TRUE(loggedIn.expiry() > now + customExpiry - 60_s);
+    ASSERT_FALSE(loggedIn.hasExpired());
+}
+
+TEST(LoggedInStatus, RenewedExpiry)
+{
+    RegistrableDomain loginDomain { URL { { }, "https://login.example.com"_s } };
+
+    auto customExpiry = LoggedInStatus::TimeToLiveShort - 48_h;
+    auto loggedInResult = LoggedInStatus::create(loginDomain, "admin"_s, LoggedInStatus::CredentialTokenType::HTTPStateToken, LoggedInStatus::AuthenticationType::WebAuthn, customExpiry);
+    auto& loggedIn = loggedInResult.releaseReturnValue().get();
+    auto now = WallTime::now();
+    ASSERT_EQ(loggedIn.authenticationType(), LoggedInStatus::AuthenticationType::WebAuthn);
+    ASSERT_TRUE(loggedIn.expiry() < now + customExpiry + 60_s);
+    ASSERT_TRUE(loggedIn.expiry() > now + customExpiry - 60_s);
+    ASSERT_FALSE(loggedIn.hasExpired());
+    auto newCustomExpiry = 24_h;
+    loggedIn.setTimeToLive(newCustomExpiry);
+    ASSERT_EQ(loggedIn.authenticationType(), LoggedInStatus::AuthenticationType::WebAuthn);
+    ASSERT_TRUE(loggedIn.expiry() < now + newCustomExpiry + 60_s);
+    ASSERT_TRUE(loggedIn.expiry() > now + newCustomExpiry - 60_s);
+    ASSERT_FALSE(loggedIn.hasExpired());
+}
+
+// Negative test cases.
+
+TEST(LoggedInStatus, InvalidUsernames)
+{
+    RegistrableDomain loginDomain { URL { { }, "https://login.example.com"_s } };
+
+    // Whitespace is not allowed.
+    auto loggedInResult = LoggedInStatus::create(loginDomain, "I use spaces"_s, LoggedInStatus::CredentialTokenType::HTTPStateToken, LoggedInStatus::AuthenticationType::WebAuthn);
+    ASSERT_TRUE(loggedInResult.hasException());
+
+    // Newlines are not allowed.
+    loggedInResult = LoggedInStatus::create(loginDomain, "Enter\nreturn"_s, LoggedInStatus::CredentialTokenType::HTTPStateToken, LoggedInStatus::AuthenticationType::WebAuthn);
+    ASSERT_TRUE(loggedInResult.hasException());
+
+    // There is a max length to usernames.
+    StringBuilder builder;
+    for (unsigned i = 0; i <= LoggedInStatus::UsernameMaxLength; ++i)
+        builder.append('a');
+    loggedInResult = LoggedInStatus::create(loginDomain, builder.toString(), LoggedInStatus::CredentialTokenType::HTTPStateToken, LoggedInStatus::AuthenticationType::WebAuthn);
+    ASSERT_TRUE(loggedInResult.hasException());
+}
+
+TEST(LoggedInStatus, ClampedExpiryLong)
+{
+    RegistrableDomain loginDomain { URL { { }, "https://login.example.com"_s } };
+
+    // Too long expiries for managed auth types should be clamped to LoggedInStatus::TimeToLiveLong.
+    auto loggedInResult = LoggedInStatus::create(loginDomain, "admin"_s, LoggedInStatus::CredentialTokenType::HTTPStateToken, LoggedInStatus::AuthenticationType::WebAuthn, LoggedInStatus::TimeToLiveLong + 24_h);
+    auto& loggedIn = loggedInResult.releaseReturnValue().get();
+    auto now = WallTime::now();
+    ASSERT_EQ(loggedIn.authenticationType(), LoggedInStatus::AuthenticationType::WebAuthn);
+    ASSERT_TRUE(loggedIn.expiry() < now + LoggedInStatus::TimeToLiveLong + 60_s);
+    ASSERT_TRUE(loggedIn.expiry() > now + LoggedInStatus::TimeToLiveLong - 60_s);
+    ASSERT_FALSE(loggedIn.hasExpired());
+
+    // Renewed, too long expiries for managed auth types should also be clamped to LoggedInStatus::TimeToLiveLong.
+    auto newCustomExpiry = LoggedInStatus::TimeToLiveLong + 24_h;
+    loggedIn.setTimeToLive(newCustomExpiry);
+    ASSERT_EQ(loggedIn.authenticationType(), LoggedInStatus::AuthenticationType::WebAuthn);
+    ASSERT_TRUE(loggedIn.expiry() < now + LoggedInStatus::TimeToLiveLong + 60_s);
+    ASSERT_TRUE(loggedIn.expiry() > now + LoggedInStatus::TimeToLiveLong - 60_s);
+    ASSERT_FALSE(loggedIn.hasExpired());
+}
+
+TEST(LoggedInStatus, ClampedExpiryShort)
+{
+    RegistrableDomain loginDomain { URL { { }, "https://login.example.com"_s } };
+
+    // Too long expiries for unmanaged auth types should be clamped to LoggedInStatus::TimeToLiveShort.
+    auto loggedInResult = LoggedInStatus::create(loginDomain, "admin"_s, LoggedInStatus::CredentialTokenType::HTTPStateToken, LoggedInStatus::AuthenticationType::Unmanaged, LoggedInStatus::TimeToLiveShort + 24_h);
+    auto& loggedIn = loggedInResult.releaseReturnValue().get();
+    auto now = WallTime::now();
+    ASSERT_EQ(loggedIn.authenticationType(), LoggedInStatus::AuthenticationType::Unmanaged);
+    ASSERT_TRUE(loggedIn.expiry() < now + LoggedInStatus::TimeToLiveShort + 60_s);
+    ASSERT_TRUE(loggedIn.expiry() > now + LoggedInStatus::TimeToLiveShort - 60_s);
+    ASSERT_FALSE(loggedIn.hasExpired());
+
+    // Renewed, too long expiries for unmanaged auth types should also be clamped to LoggedInStatus::TimeToLiveShort.
+    auto newCustomExpiry = LoggedInStatus::TimeToLiveShort + 24_h;
+    loggedIn.setTimeToLive(newCustomExpiry);
+    ASSERT_EQ(loggedIn.authenticationType(), LoggedInStatus::AuthenticationType::Unmanaged);
+    ASSERT_TRUE(loggedIn.expiry() < now + LoggedInStatus::TimeToLiveShort + 60_s);
+    ASSERT_TRUE(loggedIn.expiry() > now + LoggedInStatus::TimeToLiveShort - 60_s);
+    ASSERT_FALSE(loggedIn.hasExpired());
+}
+
+} // namespace TestWebKitAPI
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to