Diff
Modified: trunk/LayoutTests/ChangeLog (251644 => 251645)
--- trunk/LayoutTests/ChangeLog 2019-10-27 22:12:20 UTC (rev 251644)
+++ trunk/LayoutTests/ChangeLog 2019-10-27 22:53:33 UTC (rev 251645)
@@ -1,3 +1,15 @@
+2019-10-21 Jiewen Tan <[email protected]>
+
+ [WebAuthn] Warn users when multiple NFC tags present
+ https://bugs.webkit.org/show_bug.cgi?id=200932
+ <rdar://problem/54890736>
+
+ Reviewed by Brent Fulgham.
+
+ * http/wpt/webauthn/public-key-credential-create-success-nfc.https-expected.txt:
+ * http/wpt/webauthn/public-key-credential-create-success-nfc.https.html:
+ Adds new tests for multiple physical tags and service restart.
+
2019-10-27 Simon Fraser <[email protected]>
Import css/css-position WPT
Modified: trunk/LayoutTests/http/wpt/webauthn/public-key-credential-create-success-nfc.https-expected.txt (251644 => 251645)
--- trunk/LayoutTests/http/wpt/webauthn/public-key-credential-create-success-nfc.https-expected.txt 2019-10-27 22:12:20 UTC (rev 251644)
+++ trunk/LayoutTests/http/wpt/webauthn/public-key-credential-create-success-nfc.https-expected.txt 2019-10-27 22:53:33 UTC (rev 251645)
@@ -3,4 +3,6 @@
PASS PublicKeyCredential's [[create]] with authenticatorSelection { 'cross-platform' } in a mock nfc authenticator.
PASS PublicKeyCredential's [[create]] with multiple tags in a mock nfc authenticator.
PASS PublicKeyCredential's [[create]] with U2F in a mock nfc authenticator.
+PASS PublicKeyCredential's [[create]] with multiple physical tags in a mock nfc authenticator.
+PASS PublicKeyCredential's [[create]] with service restart in a mock nfc authenticator.
Modified: trunk/LayoutTests/http/wpt/webauthn/public-key-credential-create-success-nfc.https.html (251644 => 251645)
--- trunk/LayoutTests/http/wpt/webauthn/public-key-credential-create-success-nfc.https.html 2019-10-27 22:12:20 UTC (rev 251644)
+++ trunk/LayoutTests/http/wpt/webauthn/public-key-credential-create-success-nfc.https.html 2019-10-27 22:53:33 UTC (rev 251645)
@@ -21,8 +21,7 @@
displayName: "Appleseed",
},
challenge: Base64URL.parse("MTIzNDU2"),
- pubKeyCredParams: [{ type: "public-key", alg: -7 }],
- timeout: 100
+ pubKeyCredParams: [{ type: "public-key", alg: -7 }]
}
};
@@ -44,8 +43,7 @@
},
challenge: Base64URL.parse("MTIzNDU2"),
pubKeyCredParams: [{ type: "public-key", alg: -7 }],
- authenticatorSelection: { authenticatorAttachment: "cross-platform" },
- timeout: 100
+ authenticatorSelection: { authenticatorAttachment: "cross-platform" }
}
};
@@ -66,8 +64,7 @@
displayName: "Appleseed",
},
challenge: Base64URL.parse("MTIzNDU2"),
- pubKeyCredParams: [{ type: "public-key", alg: -7 }],
- timeout: 100
+ pubKeyCredParams: [{ type: "public-key", alg: -7 }]
}
};
@@ -90,8 +87,7 @@
displayName: "Appleseed",
},
challenge: Base64URL.parse("MTIzNDU2"),
- pubKeyCredParams: [{ type: "public-key", alg: -7 }],
- timeout: 100
+ pubKeyCredParams: [{ type: "public-key", alg: -7 }]
}
};
@@ -101,4 +97,50 @@
checkU2fMakeCredentialResult(credential);
});
}, "PublicKeyCredential's [[create]] with U2F in a mock nfc authenticator.");
+
+ promise_test(t => {
+ const options = {
+ publicKey: {
+ rp: {
+ name: "localhost",
+ },
+ user: {
+ name: "John Appleseed",
+ id: Base64URL.parse(testUserhandleBase64),
+ displayName: "Appleseed",
+ },
+ challenge: Base64URL.parse("MTIzNDU2"),
+ pubKeyCredParams: [{ type: "public-key", alg: -7 }]
+ }
+ };
+
+ if (window.internals)
+ internals.setMockWebAuthenticationConfiguration({ nfc: { error: "success", payloadBase64: [testNfcCtapVersionBase64, testGetInfoResponseApduBase64, testCreationMessageApduBase64], multiplePhysicalTags: true } });
+ return navigator.credentials.create(options).then(credential => {
+ checkCtapMakeCredentialResult(credential);
+ });
+ }, "PublicKeyCredential's [[create]] with multiple physical tags in a mock nfc authenticator.");
+
+ promise_test(t => {
+ const options = {
+ publicKey: {
+ rp: {
+ name: "localhost",
+ },
+ user: {
+ name: "John Appleseed",
+ id: Base64URL.parse(testUserhandleBase64),
+ displayName: "Appleseed",
+ },
+ challenge: Base64URL.parse("MTIzNDU2"),
+ pubKeyCredParams: [{ type: "public-key", alg: -7 }]
+ }
+ };
+
+ if (window.internals)
+ internals.setMockWebAuthenticationConfiguration({ silentFailure: true, nfc: { error: "malicious-payload", payloadBase64: [testDummyMessagePayloadBase64, testNfcCtapVersionBase64, testGetInfoResponseApduBase64, testCreationMessageApduBase64] } });
+ return navigator.credentials.create(options).then(credential => {
+ checkCtapMakeCredentialResult(credential);
+ });
+ }, "PublicKeyCredential's [[create]] with service restart in a mock nfc authenticator.");
</script>
Modified: trunk/Source/WebCore/ChangeLog (251644 => 251645)
--- trunk/Source/WebCore/ChangeLog 2019-10-27 22:12:20 UTC (rev 251644)
+++ trunk/Source/WebCore/ChangeLog 2019-10-27 22:53:33 UTC (rev 251645)
@@ -1,3 +1,19 @@
+2019-10-21 Jiewen Tan <[email protected]>
+
+ [WebAuthn] Warn users when multiple NFC tags present
+ https://bugs.webkit.org/show_bug.cgi?id=200932
+ <rdar://problem/54890736>
+
+ Reviewed by Brent Fulgham.
+
+ Covered by new tests in existing test file.
+
+ * testing/MockWebAuthenticationConfiguration.h:
+ (WebCore::MockWebAuthenticationConfiguration::NfcConfiguration::encode const):
+ (WebCore::MockWebAuthenticationConfiguration::NfcConfiguration::decode):
+ * testing/MockWebAuthenticationConfiguration.idl:
+ Adds a new test option.
+
2019-10-27 Antti Koivisto <[email protected]>
Move resolving direction and writing mode to PropertyCascade
Modified: trunk/Source/WebCore/testing/MockWebAuthenticationConfiguration.h (251644 => 251645)
--- trunk/Source/WebCore/testing/MockWebAuthenticationConfiguration.h 2019-10-27 22:12:20 UTC (rev 251644)
+++ trunk/Source/WebCore/testing/MockWebAuthenticationConfiguration.h 2019-10-27 22:53:33 UTC (rev 251645)
@@ -93,6 +93,7 @@
NfcError error { NfcError::Success };
Vector<String> payloadBase64;
bool multipleTags { false };
+ bool multiplePhysicalTags { false };
template<class Encoder> void encode(Encoder&) const;
template<class Decoder> static Optional<NfcConfiguration> decode(Decoder&);
@@ -193,7 +194,7 @@
template<class Encoder>
void MockWebAuthenticationConfiguration::NfcConfiguration::encode(Encoder& encoder) const
{
- encoder << error << payloadBase64 << multipleTags;
+ encoder << error << payloadBase64 << multipleTags << multiplePhysicalTags;
}
template<class Decoder>
@@ -206,6 +207,8 @@
return WTF::nullopt;
if (!decoder.decode(result.multipleTags))
return WTF::nullopt;
+ if (!decoder.decode(result.multiplePhysicalTags))
+ return WTF::nullopt;
return result;
}
Modified: trunk/Source/WebCore/testing/MockWebAuthenticationConfiguration.idl (251644 => 251645)
--- trunk/Source/WebCore/testing/MockWebAuthenticationConfiguration.idl 2019-10-27 22:12:20 UTC (rev 251644)
+++ trunk/Source/WebCore/testing/MockWebAuthenticationConfiguration.idl 2019-10-27 22:53:33 UTC (rev 251645)
@@ -100,4 +100,5 @@
MockNfcError error = "success";
sequence<DOMString> payloadBase64;
boolean multipleTags = false;
+ boolean multiplePhysicalTags = false;
};
Modified: trunk/Source/WebKit/ChangeLog (251644 => 251645)
--- trunk/Source/WebKit/ChangeLog 2019-10-27 22:12:20 UTC (rev 251644)
+++ trunk/Source/WebKit/ChangeLog 2019-10-27 22:53:33 UTC (rev 251645)
@@ -1,3 +1,76 @@
+2019-10-21 Jiewen Tan <[email protected]>
+
+ [WebAuthn] Warn users when multiple NFC tags present
+ https://bugs.webkit.org/show_bug.cgi?id=200932
+ <rdar://problem/54890736>
+
+ Reviewed by Brent Fulgham.
+
+ This patch utilizes -[_WKWebAuthenticationPanelDelegate panel:updateWebAuthenticationPanel:] to
+ inform clients about multiple physical tags are presenting such that clients can instruct users
+ to select only one of them physically. Given a physical tag could have multiple different
+ interfaces, which NearField will treat them into different NFTags, the tagID is then used to
+ identify if there are actually multiple physical tags.
+
+ This patch also adds the ability to restart polling of a partiuclar NFReaderSession to NfcConnection
+ and the ability to restart the whole session to NfcService. The former is used to recover from errors
+ in the discovery stages, and the latter is used to recover from errors returned from authenticators
+ in the request stages. For the latter, given NfcConnection is not awared of the syntax of FIDO2/U2F
+ protocol, and CtapAuthenticator/U2fAuthenticator are not awared the transport of the underneath driver.
+ A generic restartDiscovery process is added to each service and it is up to the actual service to
+ implement the actual process such that AuthenticatorManager can arbitrarily call it after exceptions
+ are returned to restart the whole NFC session. To achieve restartDiscovery, NfcConnection is made
+ RefCounted as well such that both the NfcService and the CtapNfcDriver could hold it at the same time.
+ CtapNfcDriver uses the connection to complete requests as before while NfcService has the new capability
+ to use it to stop the current session when restartDiscovery kicks off.
+
+ * Platform/spi/Cocoa/NearFieldSPI.h:
+ * UIProcess/WebAuthentication/AuthenticatorManager.cpp:
+ (WebKit::AuthenticatorManager::serviceStatusUpdated):
+ (WebKit::AuthenticatorManager::respondReceived):
+ (WebKit::AuthenticatorManager::restartDiscovery):
+ * UIProcess/WebAuthentication/AuthenticatorManager.h:
+ * UIProcess/WebAuthentication/AuthenticatorTransportService.cpp:
+ (WebKit::AuthenticatorTransportService::startDiscovery):
+ (WebKit::AuthenticatorTransportService::restartDiscovery):
+ * UIProcess/WebAuthentication/AuthenticatorTransportService.h:
+ (WebKit::AuthenticatorTransportService::restartDiscoveryInternal):
+ * UIProcess/WebAuthentication/Cocoa/NfcConnection.h:
+ * UIProcess/WebAuthentication/Cocoa/NfcConnection.mm:
+ (WebKit::NfcConnection::create):
+ (WebKit::NfcConnection::NfcConnection):
+ (WebKit::NfcConnection::~NfcConnection):
+ (WebKit::NfcConnection::stop const):
+ (WebKit::NfcConnection::didDetectTags):
+ (WebKit::NfcConnection::restartPolling):
+ (WebKit::NfcConnection::startPolling):
+ (WebKit::NfcConnection::didDetectTags const): Deleted.
+ * UIProcess/WebAuthentication/Cocoa/NfcService.h:
+ * UIProcess/WebAuthentication/Cocoa/NfcService.mm:
+ (WebKit::NfcService::NfcService):
+ (WebKit::NfcService::didConnectTag):
+ (WebKit::NfcService::didDetectMultipleTags const):
+ (WebKit::NfcService::setConnection):
+ (WebKit::NfcService::restartDiscoveryInternal):
+ (WebKit::NfcService::platformStartDiscovery):
+ (WebKit::NfcService::setDriver): Deleted.
+ * UIProcess/WebAuthentication/Mock/MockNfcService.h:
+ * UIProcess/WebAuthentication/Mock/MockNfcService.mm:
+ (-[WKMockNFTag tagID]):
+ (-[WKMockNFTag initWithNFTag:]):
+ (-[WKMockNFTag dealloc]):
+ (-[WKMockNFTag initWithType:]):
+ (-[WKMockNFTag initWithType:tagID:]):
+ (WebKit::MockNfcService::receiveStopPolling):
+ (WebKit::MockNfcService::receiveStartPolling):
+ (WebKit::MockNfcService::platformStartDiscovery):
+ (WebKit::MockNfcService::detectTags):
+ (WebKit::MockNfcService::detectTags const): Deleted.
+ * UIProcess/WebAuthentication/fido/CtapNfcDriver.cpp:
+ (WebKit::CtapNfcDriver::CtapNfcDriver):
+ * UIProcess/WebAuthentication/fido/CtapNfcDriver.h:
+ * UIProcess/WebAuthentication/fido/U2fAuthenticator.cpp:
+
2019-10-26 youenn fablet <[email protected]>
Enforce user gesture for getUserMedia in case a previous getUserMedia call was denied
Modified: trunk/Source/WebKit/Platform/spi/Cocoa/NearFieldSPI.h (251644 => 251645)
--- trunk/Source/WebKit/Platform/spi/Cocoa/NearFieldSPI.h 2019-10-27 22:12:20 UTC (rev 251644)
+++ trunk/Source/WebKit/Platform/spi/Cocoa/NearFieldSPI.h 2019-10-27 22:53:33 UTC (rev 251645)
@@ -93,12 +93,11 @@
@interface NFReaderSession : NFSession
@property (assign) id<NFReaderSessionDelegate> delegate;
-- (BOOL)startPolling;
+- (BOOL)startPollingWithError:(NSError **)outError;
- (BOOL)stopPolling;
- (BOOL)connectTag:(NFTag*)tag;
- (BOOL)disconnectTag;
- (NSData*)transceive:(NSData*)capdu;
-- (NSError *)updateUIAlertMessage:(NSString *)message;
@end
@protocol NFReaderSessionDelegate <NSObject>
Modified: trunk/Source/WebKit/UIProcess/WebAuthentication/AuthenticatorManager.cpp (251644 => 251645)
--- trunk/Source/WebKit/UIProcess/WebAuthentication/AuthenticatorManager.cpp 2019-10-27 22:12:20 UTC (rev 251644)
+++ trunk/Source/WebKit/UIProcess/WebAuthentication/AuthenticatorManager.cpp 2019-10-27 22:53:33 UTC (rev 251645)
@@ -213,6 +213,12 @@
ASSERT_UNUSED(addResult, addResult.isNewEntry);
}
+void AuthenticatorManager::serviceStatusUpdated(WebAuthenticationStatus status)
+{
+ if (auto *panel = m_pendingRequestData.panel.get())
+ panel->client().updatePanel(status);
+}
+
void AuthenticatorManager::respondReceived(Respond&& respond)
{
ASSERT(RunLoop::isMain());
@@ -230,6 +236,7 @@
return;
}
respondReceivedInternal(WTFMove(respond));
+ restartDiscovery();
}
void AuthenticatorManager::downgrade(Authenticator* id, Ref<Authenticator>&& downgradedAuthenticator)
@@ -345,6 +352,12 @@
m_pendingRequestData = { };
}
+void AuthenticatorManager::restartDiscovery()
+{
+ for (auto& service : m_services)
+ service->restartDiscovery();
+}
+
} // namespace WebKit
#endif // ENABLE(WEB_AUTHN)
Modified: trunk/Source/WebKit/UIProcess/WebAuthentication/AuthenticatorManager.h (251644 => 251645)
--- trunk/Source/WebKit/UIProcess/WebAuthentication/AuthenticatorManager.h 2019-10-27 22:12:20 UTC (rev 251644)
+++ trunk/Source/WebKit/UIProcess/WebAuthentication/AuthenticatorManager.h 2019-10-27 22:53:33 UTC (rev 251645)
@@ -73,6 +73,7 @@
private:
// AuthenticatorTransportService::Observer
void authenticatorAdded(Ref<Authenticator>&&) final;
+ void serviceStatusUpdated(WebAuthenticationStatus) final;
// Authenticator::Observer
void respondReceived(Respond&&) final;
@@ -90,6 +91,7 @@
void runPanel();
void startRequest();
void resetState();
+ void restartDiscovery();
// Request: We only allow one request per time. A new request will cancel any pending ones.
WebAuthenticationRequestData m_pendingRequestData;
Modified: trunk/Source/WebKit/UIProcess/WebAuthentication/AuthenticatorTransportService.cpp (251644 => 251645)
--- trunk/Source/WebKit/UIProcess/WebAuthentication/AuthenticatorTransportService.cpp 2019-10-27 22:12:20 UTC (rev 251644)
+++ trunk/Source/WebKit/UIProcess/WebAuthentication/AuthenticatorTransportService.cpp 2019-10-27 22:53:33 UTC (rev 251645)
@@ -75,7 +75,6 @@
void AuthenticatorTransportService::startDiscovery()
{
- // Enforce asynchronous execution of makeCredential.
RunLoop::main().dispatch([weakThis = makeWeakPtr(*this)] {
if (!weakThis)
return;
@@ -83,6 +82,15 @@
});
}
+void AuthenticatorTransportService::restartDiscovery()
+{
+ RunLoop::main().dispatch([weakThis = makeWeakPtr(*this)] {
+ if (!weakThis)
+ return;
+ weakThis->restartDiscoveryInternal();
+ });
+}
+
} // namespace WebKit
#endif // ENABLE(WEB_AUTHN)
Modified: trunk/Source/WebKit/UIProcess/WebAuthentication/AuthenticatorTransportService.h (251644 => 251645)
--- trunk/Source/WebKit/UIProcess/WebAuthentication/AuthenticatorTransportService.h 2019-10-27 22:12:20 UTC (rev 251644)
+++ trunk/Source/WebKit/UIProcess/WebAuthentication/AuthenticatorTransportService.h 2019-10-27 22:53:33 UTC (rev 251645)
@@ -27,6 +27,7 @@
#if ENABLE(WEB_AUTHN)
+#include "WebAuthenticationFlags.h"
#include <WebCore/AuthenticatorTransport.h>
#include <wtf/UniqueRef.h>
#include <wtf/WeakPtr.h>
@@ -48,6 +49,7 @@
virtual ~Observer() = default;
virtual void authenticatorAdded(Ref<Authenticator>&&) = 0;
+ virtual void serviceStatusUpdated(WebAuthenticationStatus) = 0;
};
static UniqueRef<AuthenticatorTransportService> create(WebCore::AuthenticatorTransport, Observer&);
@@ -55,8 +57,9 @@
virtual ~AuthenticatorTransportService() = default;
- // This operation is guaranteed to execute asynchronously.
+ // These operations are guaranteed to execute asynchronously.
void startDiscovery();
+ void restartDiscovery();
protected:
explicit AuthenticatorTransportService(Observer&);
@@ -65,6 +68,9 @@
private:
virtual void startDiscoveryInternal() = 0;
+ // NFC service's polling is one shot. It halts after the first tags are detected.
+ // Therefore, a restart process is needed to resume polling after exceptions.
+ virtual void restartDiscoveryInternal() { };
WeakPtr<Observer> m_observer;
};
Modified: trunk/Source/WebKit/UIProcess/WebAuthentication/Cocoa/NfcConnection.h (251644 => 251645)
--- trunk/Source/WebKit/UIProcess/WebAuthentication/Cocoa/NfcConnection.h 2019-10-27 22:12:20 UTC (rev 251644)
+++ trunk/Source/WebKit/UIProcess/WebAuthentication/Cocoa/NfcConnection.h 2019-10-27 22:53:33 UTC (rev 251645)
@@ -27,9 +27,9 @@
#if ENABLE(WEB_AUTHN) && HAVE(NEAR_FIELD)
-#include <wtf/FastMalloc.h>
-#include <wtf/Noncopyable.h>
+#include <wtf/RefCounted.h>
#include <wtf/RetainPtr.h>
+#include <wtf/RunLoop.h>
#include <wtf/WeakPtr.h>
OBJC_CLASS NFReaderSession;
@@ -40,22 +40,27 @@
class NfcService;
-class NfcConnection : public CanMakeWeakPtr<NfcConnection> {
- WTF_MAKE_FAST_ALLOCATED;
- WTF_MAKE_NONCOPYABLE(NfcConnection);
+class NfcConnection : public RefCounted<NfcConnection>, public CanMakeWeakPtr<NfcConnection> {
public:
- NfcConnection(RetainPtr<NFReaderSession>&&, NfcService&);
+ static Ref<NfcConnection> create(RetainPtr<NFReaderSession>&&, NfcService&);
~NfcConnection();
Vector<uint8_t> transact(Vector<uint8_t>&& data) const;
+ void stop() const;
// For WKNFReaderSessionDelegate
- void didDetectTags(NSArray *) const;
+ void didDetectTags(NSArray *);
private:
+ NfcConnection(RetainPtr<NFReaderSession>&&, NfcService&);
+
+ void restartPolling();
+ void startPolling();
+
RetainPtr<NFReaderSession> m_session;
RetainPtr<WKNFReaderSessionDelegate> m_delegate;
WeakPtr<NfcService> m_service;
+ RunLoop::Timer<NfcConnection> m_retryTimer;
};
} // namespace WebKit
Modified: trunk/Source/WebKit/UIProcess/WebAuthentication/Cocoa/NfcConnection.mm (251644 => 251645)
--- trunk/Source/WebKit/UIProcess/WebAuthentication/Cocoa/NfcConnection.mm 2019-10-27 22:12:20 UTC (rev 251644)
+++ trunk/Source/WebKit/UIProcess/WebAuthentication/Cocoa/NfcConnection.mm 2019-10-27 22:53:33 UTC (rev 251645)
@@ -45,20 +45,24 @@
}
} // namespace
+Ref<NfcConnection> NfcConnection::create(RetainPtr<NFReaderSession>&& session, NfcService& service)
+{
+ return adoptRef(*new NfcConnection(WTFMove(session), service));
+}
+
NfcConnection::NfcConnection(RetainPtr<NFReaderSession>&& session, NfcService& service)
: m_session(WTFMove(session))
, m_delegate(adoptNS([[WKNFReaderSessionDelegate alloc] initWithConnection:*this]))
, m_service(makeWeakPtr(service))
+ , m_retryTimer(RunLoop::main(), this, &NfcConnection::startPolling)
{
[m_session setDelegate:m_delegate.get()];
- [m_session startPolling];
+ startPolling();
}
NfcConnection::~NfcConnection()
{
- [m_session disconnectTag];
- [m_session stopPolling];
- [m_session endSession];
+ stop();
}
Vector<uint8_t> NfcConnection::transact(Vector<uint8_t>&& data) const
@@ -71,16 +75,33 @@
return response;
}
-void NfcConnection::didDetectTags(NSArray *tags) const
+void NfcConnection::stop() const
{
- if (!m_service)
+ [m_session disconnectTag];
+ [m_session stopPolling];
+ [m_session endSession];
+}
+
+void NfcConnection::didDetectTags(NSArray *tags)
+{
+ if (!m_service || !tags.count)
return;
- // FIXME(200932): Warn users when multiple NFC tags present
- for (NFTag *tag in tags) {
- if (tag.type != NFTagTypeGeneric4A)
+ // A physical NFC tag could have multiple interfaces.
+ // Therefore, we use tagID to detect if there are multiple physical tags.
+ NSData *tagID = ((NFTag *)tags[0]).tagID;
+ for (NFTag *tag : tags) {
+ if ([tagID isEqualToData:tag.tagID])
continue;
- if (![m_session connectTag:tag])
+ m_service->didDetectMultipleTags();
+ restartPolling();
+ return;
+ }
+
+ // FIXME(203234): Tell users to switch to a different tag if the tag is not of type NFTagTypeGeneric4A
+ // or can't speak U2F/FIDO2.
+ for (NFTag *tag : tags) {
+ if (tag.type != NFTagTypeGeneric4A || ![m_session connectTag:tag])
continue;
// Confirm the FIDO applet is avaliable before return.
@@ -94,10 +115,27 @@
}
m_service->didConnectTag();
- break;
+ return;
}
+ restartPolling();
}
+// NearField polling is a one shot polling. It halts after tags are detected.
+// Therefore, a restart process is needed to resume polling after error.
+void NfcConnection::restartPolling()
+{
+ [m_session stopPolling];
+ m_retryTimer.startOneShot(1_s); // Magic number to give users enough time for reactions.
+}
+
+void NfcConnection::startPolling()
+{
+ NSError *error = nil;
+ [m_session startPollingWithError:&error];
+ if (error)
+ LOG_ERROR("Couldn't start NFC reader polling: %@", error);
+}
+
} // namespace WebKit
#endif // ENABLE(WEB_AUTHN) && HAVE(NEAR_FIELD)
Modified: trunk/Source/WebKit/UIProcess/WebAuthentication/Cocoa/NfcService.h (251644 => 251645)
--- trunk/Source/WebKit/UIProcess/WebAuthentication/Cocoa/NfcService.h 2019-10-27 22:12:20 UTC (rev 251644)
+++ trunk/Source/WebKit/UIProcess/WebAuthentication/Cocoa/NfcService.h 2019-10-27 22:53:33 UTC (rev 251645)
@@ -28,12 +28,13 @@
#if ENABLE(WEB_AUTHN)
#include "FidoService.h"
+#include <wtf/RunLoop.h>
OBJC_CLASS NFReaderSession;
namespace WebKit {
-class CtapNfcDriver;
+class NfcConnection;
class NfcService : public FidoService {
public:
@@ -42,15 +43,16 @@
// For NfcConnection.
void didConnectTag();
+ void didDetectMultipleTags() const;
#if HAVE(NEAR_FIELD)
protected:
- void setDriver(std::unique_ptr<CtapNfcDriver>&&);
+ void setConnection(Ref<NfcConnection>&&); // For MockNfcConnection
#endif
private:
void startDiscoveryInternal() final;
- void continueAddDeviceAfterGetInfo(Vector<uint8_t>&& response);
+ void restartDiscoveryInternal() final;
// Overrided by MockNfcService.
virtual void platformStartDiscovery();
@@ -58,8 +60,9 @@
#if HAVE(NEAR_FIELD)
// Only one reader session is allowed per time.
// Keep the reader session alive here when it tries to connect to a tag.
- std::unique_ptr<CtapNfcDriver> m_driver;
+ RefPtr<NfcConnection> m_connection;
#endif
+ RunLoop::Timer<NfcService> m_restartTimer;
};
} // namespace WebKit
Modified: trunk/Source/WebKit/UIProcess/WebAuthentication/Cocoa/NfcService.mm (251644 => 251645)
--- trunk/Source/WebKit/UIProcess/WebAuthentication/Cocoa/NfcService.mm 2019-10-27 22:12:20 UTC (rev 251644)
+++ trunk/Source/WebKit/UIProcess/WebAuthentication/Cocoa/NfcService.mm 2019-10-27 22:53:33 UTC (rev 251645)
@@ -41,6 +41,7 @@
NfcService::NfcService(Observer& observer)
: FidoService(observer)
+ , m_restartTimer(RunLoop::main(), this, &NfcService::platformStartDiscovery)
{
}
@@ -51,14 +52,22 @@
void NfcService::didConnectTag()
{
#if HAVE(NEAR_FIELD)
- getInfo(WTFMove(m_driver));
+ auto connection = m_connection;
+ ASSERT(connection);
+ getInfo(WTF::makeUnique<CtapNfcDriver>(connection.releaseNonNull()));
#endif
}
+void NfcService::didDetectMultipleTags() const
+{
+ if (auto* observer = this->observer())
+ observer->serviceStatusUpdated(WebAuthenticationStatus::MultipleNFCTagsPresent);
+}
+
#if HAVE(NEAR_FIELD)
-void NfcService::setDriver(std::unique_ptr<CtapNfcDriver>&& driver)
+void NfcService::setConnection(Ref<NfcConnection>&& connection)
{
- m_driver = WTFMove(driver);
+ m_connection = WTFMove(connection);
}
#endif
@@ -67,6 +76,15 @@
platformStartDiscovery();
}
+void NfcService::restartDiscoveryInternal()
+{
+#if HAVE(NEAR_FIELD)
+ if (m_connection)
+ m_connection->stop();
+#endif
+ m_restartTimer.startOneShot(1_s); // Magic number to give users enough time for reactions.
+}
+
void NfcService::platformStartDiscovery()
{
#if HAVE(NEAR_FIELD)
@@ -87,8 +105,8 @@
return;
}
- // CtapNfcDriver and NfcConnection will take care of polling tags and connecting to them.
- m_driver = WTF::makeUnique<CtapNfcDriver>(makeUniqueRef<NfcConnection>(WTFMove(session), *this));
+ // NfcConnection will take care of polling tags and connecting to them.
+ m_connection = NfcConnection::create(WTFMove(session), *this);
});
});
[[getNFHardwareManagerClass() sharedHardwareManager] startReaderSession:callback.get()];
Modified: trunk/Source/WebKit/UIProcess/WebAuthentication/Mock/MockNfcService.h (251644 => 251645)
--- trunk/Source/WebKit/UIProcess/WebAuthentication/Mock/MockNfcService.h 2019-10-27 22:12:20 UTC (rev 251644)
+++ trunk/Source/WebKit/UIProcess/WebAuthentication/Mock/MockNfcService.h 2019-10-27 22:53:33 UTC (rev 251645)
@@ -39,6 +39,8 @@
MockNfcService(Observer&, const WebCore::MockWebAuthenticationConfiguration&);
NSData* transceive();
+ void receiveStopPolling();
+ void receiveStartPolling();
private:
void platformStartDiscovery() final;
Modified: trunk/Source/WebKit/UIProcess/WebAuthentication/Mock/MockNfcService.mm (251644 => 251645)
--- trunk/Source/WebKit/UIProcess/WebAuthentication/Mock/MockNfcService.mm 2019-10-27 22:12:20 UTC (rev 251644)
+++ trunk/Source/WebKit/UIProcess/WebAuthentication/Mock/MockNfcService.mm 2019-10-27 22:53:33 UTC (rev 251645)
@@ -38,20 +38,26 @@
#import "NearFieldSoftLink.h"
+namespace {
+uint8_t tagID1[] = { 0x01 };
+uint8_t tagID2[] = { 0x02 };
+}
+
#if HAVE(NEAR_FIELD)
@interface WKMockNFTag : NSObject <NFTag>
- (instancetype)initWithType:(NFTagType)type;
+- (instancetype)initWithType:(NFTagType)type tagID:(NSData *)tagID;
@end
@implementation WKMockNFTag {
NFTagType _type;
+ RetainPtr<NSData> _tagID;
}
@synthesize technology=_technology;
-@synthesize tagID=_tagID;
@synthesize AppData=_AppData;
@synthesize UID=_UID;
@synthesize ndefAvailability=_ndefAvailability;
@@ -66,17 +72,22 @@
return _type;
}
+- (NSData *)tagID
+{
+ return _tagID.get();
+}
+
- (instancetype)initWithNFTag:(id<NFTag>)tag
{
- if ((self = [super init]))
+ if ((self = [super init])) {
_type = tag.type;
+ _tagID = tag.tagID;
+ }
return self;
}
- (void)dealloc
{
- [_tagID release];
- _tagID = nil;
[_AppData release];
_AppData = nil;
[_UID release];
@@ -97,8 +108,15 @@
- (instancetype)initWithType:(NFTagType)type
{
- if ((self = [super init]))
+ return [self initWithType:type tagID:adoptNS([[NSData alloc] initWithBytes:tagID1 length:sizeof(tagID1)]).get()];
+}
+
+- (instancetype)initWithType:(NFTagType)type tagID:(NSData *)tagID
+{
+ if ((self = [super init])) {
_type = type;
+ _tagID = tagID;
+ }
return self;
}
@@ -132,6 +150,22 @@
return YES;
}
+static BOOL NFReaderSessionStopPolling(id, SEL)
+{
+ if (!globalNfcService)
+ return NO;
+ globalNfcService->receiveStopPolling();
+ return YES;
+}
+
+static BOOL NFReaderSessionStartPollingWithError(id, SEL, NSError **)
+{
+ if (!globalNfcService)
+ return NO;
+ globalNfcService->receiveStartPolling();
+ return YES;
+}
+
static NSData* NFReaderSessionTransceive(id, SEL, NSData *)
{
if (!globalNfcService)
@@ -159,6 +193,21 @@
return [result autorelease];
}
+void MockNfcService::receiveStopPolling()
+{
+ // For purpose of restart polling.
+ m_configuration.nfc->multiplePhysicalTags = false;
+}
+
+void MockNfcService::receiveStartPolling()
+{
+ RunLoop::main().dispatch([weakThis = makeWeakPtr(*this)] {
+ if (!weakThis)
+ return;
+ weakThis->detectTags();
+ });
+}
+
void MockNfcService::platformStartDiscovery()
{
#if HAVE(NEAR_FIELD)
@@ -177,15 +226,14 @@
Method methodToSwizzle3 = class_getInstanceMethod(getNFReaderSessionClass(), @selector(transceive:));
method_setImplementation(methodToSwizzle3, (IMP)NFReaderSessionTransceive);
+ Method methodToSwizzle4 = class_getInstanceMethod(getNFReaderSessionClass(), @selector(stopPolling));
+ method_setImplementation(methodToSwizzle4, (IMP)NFReaderSessionStopPolling);
+
+ Method methodToSwizzle5 = class_getInstanceMethod(getNFReaderSessionClass(), @selector(startPollingWithError:));
+ method_setImplementation(methodToSwizzle5, (IMP)NFReaderSessionStartPollingWithError);
+
auto readerSession = adoptNS([allocNFReaderSessionInstance() init]);
- setDriver(WTF::makeUnique<CtapNfcDriver>(makeUniqueRef<NfcConnection>(readerSession.get(), *this)));
-
- RunLoop::main().dispatch([weakThis = makeWeakPtr(*this)] {
- if (!weakThis)
- return;
- weakThis->detectTags();
- });
- return;
+ setConnection(NfcConnection::create(readerSession.get(), *this));
}
LOG_ERROR("No nfc authenticators is available.");
#endif // HAVE(NEAR_FIELD)
@@ -207,6 +255,9 @@
if (configuration.nfc->multipleTags)
[tags addObject:adoptNS([[WKMockNFTag alloc] initWithType:NFTagTypeGeneric4A]).get()];
+ if (configuration.nfc->multiplePhysicalTags)
+ [tags addObject:adoptNS([[WKMockNFTag alloc] initWithType:NFTagTypeGeneric4A tagID:adoptNS([[NSData alloc] initWithBytes:tagID2 length:sizeof(tagID2)]).get()]).get()];
+
[globalNFReaderSessionDelegate readerSession:nil didDetectTags:tags.get()];
});
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), callback.get());
Modified: trunk/Source/WebKit/UIProcess/WebAuthentication/fido/CtapNfcDriver.cpp (251644 => 251645)
--- trunk/Source/WebKit/UIProcess/WebAuthentication/fido/CtapNfcDriver.cpp 2019-10-27 22:12:20 UTC (rev 251644)
+++ trunk/Source/WebKit/UIProcess/WebAuthentication/fido/CtapNfcDriver.cpp 2019-10-27 22:53:33 UTC (rev 251645)
@@ -36,7 +36,7 @@
using namespace apdu;
using namespace fido;
-CtapNfcDriver::CtapNfcDriver(UniqueRef<NfcConnection>&& connection)
+CtapNfcDriver::CtapNfcDriver(Ref<NfcConnection>&& connection)
: m_connection(WTFMove(connection))
{
}
Modified: trunk/Source/WebKit/UIProcess/WebAuthentication/fido/CtapNfcDriver.h (251644 => 251645)
--- trunk/Source/WebKit/UIProcess/WebAuthentication/fido/CtapNfcDriver.h 2019-10-27 22:12:20 UTC (rev 251644)
+++ trunk/Source/WebKit/UIProcess/WebAuthentication/fido/CtapNfcDriver.h 2019-10-27 22:53:33 UTC (rev 251645)
@@ -37,7 +37,7 @@
// https://fidoalliance.org/specs/fido-v2.0-ps-20190130/fido-client-to-authenticator-protocol-v2.0-ps-20190130.html#nfc
class CtapNfcDriver : public CtapDriver {
public:
- explicit CtapNfcDriver(UniqueRef<NfcConnection>&&);
+ explicit CtapNfcDriver(Ref<NfcConnection>&&);
void transact(Vector<uint8_t>&& data, ResponseCallback&&) final;
@@ -44,7 +44,7 @@
private:
void respondAsync(ResponseCallback&&, Vector<uint8_t>&& response) const;
- UniqueRef<NfcConnection> m_connection;
+ Ref<NfcConnection> m_connection;
};
} // namespace WebKit
Modified: trunk/Source/WebKit/UIProcess/WebAuthentication/fido/U2fAuthenticator.cpp (251644 => 251645)
--- trunk/Source/WebKit/UIProcess/WebAuthentication/fido/U2fAuthenticator.cpp 2019-10-27 22:12:20 UTC (rev 251644)
+++ trunk/Source/WebKit/UIProcess/WebAuthentication/fido/U2fAuthenticator.cpp 2019-10-27 22:53:33 UTC (rev 251645)
@@ -33,7 +33,6 @@
#include <WebCore/ExceptionData.h>
#include <WebCore/U2fCommandConstructor.h>
#include <WebCore/U2fResponseConverter.h>
-#include <wtf/RunLoop.h>
#include <wtf/text/StringConcatenateNumbers.h>
namespace WebKit {
Modified: trunk/Tools/ChangeLog (251644 => 251645)
--- trunk/Tools/ChangeLog 2019-10-27 22:12:20 UTC (rev 251644)
+++ trunk/Tools/ChangeLog 2019-10-27 22:53:33 UTC (rev 251645)
@@ -1,3 +1,18 @@
+2019-10-21 Jiewen Tan <[email protected]>
+
+ [WebAuthn] Warn users when multiple NFC tags present
+ https://bugs.webkit.org/show_bug.cgi?id=200932
+ <rdar://problem/54890736>
+
+ Reviewed by Brent Fulgham.
+
+ * TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj:
+ * TestWebKitAPI/Tests/WebKitCocoa/_WKWebAuthenticationPanel.mm:
+ (-[TestWebAuthenticationPanelDelegate panel:updateWebAuthenticationPanel:]):
+ (TestWebKitAPI::TEST):
+ Adds a new test for -[_WKWebAuthenticationPanelDelegate panel:updateWebAuthenticationPanel:].
+ * TestWebKitAPI/Tests/WebKitCocoa/web-authentication-get-assertion-nfc-multiple-tags.html: Added.
+
2019-10-27 Claudio Saavedra <[email protected]>
[GTK][WPE] Test PublicSuffix.TopPrivatelyControlledDomain is failing since r250589
Modified: trunk/Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj (251644 => 251645)
--- trunk/Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj 2019-10-27 22:12:20 UTC (rev 251644)
+++ trunk/Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj 2019-10-27 22:53:33 UTC (rev 251645)
@@ -350,6 +350,7 @@
579651E7216BFDED006EBFE5 /* FidoHidMessageTest.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 579651E6216BFD53006EBFE5 /* FidoHidMessageTest.cpp */; };
5797FE311EB15A6800B2F4A0 /* NavigationClientDefaultCrypto.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5797FE2F1EB15A5F00B2F4A0 /* NavigationClientDefaultCrypto.cpp */; };
5797FE331EB15AB100B2F4A0 /* navigation-client-default-crypto.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = 5797FE321EB15A8900B2F4A0 /* navigation-client-default-crypto.html */; };
+ 5798337C235EB689008E5547 /* web-authentication-get-assertion-nfc-multiple-tags.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = 5798337B235EB65C008E5547 /* web-authentication-get-assertion-nfc-multiple-tags.html */; };
57A79857224AB34E00A7F6F1 /* WebCryptoMasterKey.mm in Sources */ = {isa = PBXBuildFile; fileRef = 57A79856224AB34E00A7F6F1 /* WebCryptoMasterKey.mm */; };
57C3FA661F7C248F009D4B80 /* WeakPtr.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1CB9BC371A67482300FE5678 /* WeakPtr.cpp */; };
57C6244E2346BCFA00383FE7 /* _WKWebAuthenticationPanel.mm in Sources */ = {isa = PBXBuildFile; fileRef = 57C6244D2346BCFA00383FE7 /* _WKWebAuthenticationPanel.mm */; };
@@ -1453,6 +1454,7 @@
57663DF32357E48900E85E09 /* web-authentication-get-assertion-hid-cancel.html in Copy Resources */,
577454D02359B378008E1ED7 /* web-authentication-get-assertion-hid-no-credentials.html in Copy Resources */,
57663DEC234F1F9300E85E09 /* web-authentication-get-assertion-hid.html in Copy Resources */,
+ 5798337C235EB689008E5547 /* web-authentication-get-assertion-nfc-multiple-tags.html in Copy Resources */,
57663DEA234EA66D00E85E09 /* web-authentication-get-assertion-nfc.html in Copy Resources */,
577454D22359BB01008E1ED7 /* web-authentication-get-assertion-u2f-no-credentials.html in Copy Resources */,
57C624502346C21E00383FE7 /* web-authentication-get-assertion.html in Copy Resources */,
@@ -1889,6 +1891,7 @@
579651E6216BFD53006EBFE5 /* FidoHidMessageTest.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = FidoHidMessageTest.cpp; sourceTree = "<group>"; };
5797FE2F1EB15A5F00B2F4A0 /* NavigationClientDefaultCrypto.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = NavigationClientDefaultCrypto.cpp; sourceTree = "<group>"; };
5797FE321EB15A8900B2F4A0 /* navigation-client-default-crypto.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = "navigation-client-default-crypto.html"; sourceTree = "<group>"; };
+ 5798337B235EB65C008E5547 /* web-authentication-get-assertion-nfc-multiple-tags.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = "web-authentication-get-assertion-nfc-multiple-tags.html"; sourceTree = "<group>"; };
5798E2AF1CAF5C2800C5CBA0 /* ProvisionalURLNotChange.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = ProvisionalURLNotChange.mm; sourceTree = "<group>"; };
57A79856224AB34E00A7F6F1 /* WebCryptoMasterKey.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = WebCryptoMasterKey.mm; sourceTree = "<group>"; };
57C6244D2346BCFA00383FE7 /* _WKWebAuthenticationPanel.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = _WKWebAuthenticationPanel.mm; sourceTree = "<group>"; };
@@ -3412,6 +3415,7 @@
57663DF22357E45D00E85E09 /* web-authentication-get-assertion-hid-cancel.html */,
577454CF2359B338008E1ED7 /* web-authentication-get-assertion-hid-no-credentials.html */,
57663DEB234F1F8000E85E09 /* web-authentication-get-assertion-hid.html */,
+ 5798337B235EB65C008E5547 /* web-authentication-get-assertion-nfc-multiple-tags.html */,
57663DE9234EA60B00E85E09 /* web-authentication-get-assertion-nfc.html */,
577454D12359BAD5008E1ED7 /* web-authentication-get-assertion-u2f-no-credentials.html */,
57C6244F2346C1EC00383FE7 /* web-authentication-get-assertion.html */,
Modified: trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/_WKWebAuthenticationPanel.mm (251644 => 251645)
--- trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/_WKWebAuthenticationPanel.mm 2019-10-27 22:12:20 UTC (rev 251644)
+++ trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/_WKWebAuthenticationPanel.mm 2019-10-27 22:53:33 UTC (rev 251645)
@@ -42,6 +42,7 @@
static bool webAuthenticationPanelRan = false;
static bool webAuthenticationPanelFailed = false;
static bool webAuthenticationPanelSucceded = false;
+static bool webAuthenticationPanelUpdateMultipleNFCTagsPresent = false;
static bool webAuthenticationPanelUpdateNoCredentialsFound = false;
static RetainPtr<_WKWebAuthenticationPanel> gPanel;
@@ -53,8 +54,14 @@
- (void)panel:(_WKWebAuthenticationPanel *)panel updateWebAuthenticationPanel:(_WKWebAuthenticationPanelUpdate)update
{
ASSERT_NE(panel, nil);
- if (update == _WKWebAuthenticationPanelUpdateNoCredentialsFound)
+ if (update == _WKWebAuthenticationPanelUpdateMultipleNFCTagsPresent) {
+ webAuthenticationPanelUpdateMultipleNFCTagsPresent = true;
+ return;
+ }
+ if (update == _WKWebAuthenticationPanelUpdateNoCredentialsFound) {
webAuthenticationPanelUpdateNoCredentialsFound = true;
+ return;
+ }
}
- (void)panel:(_WKWebAuthenticationPanel *)panel dismissWebAuthenticationPanelWithResult:(_WKWebAuthenticationResult)result
@@ -606,6 +613,25 @@
[webView waitForMessage:@"Operation timed out."];
}
+#if HAVE(NEAR_FIELD)
+TEST(WebAuthenticationPanel, PanelMultipleNFCTagsPresent)
+{
+ reset();
+ RetainPtr<NSURL> testURL = [[NSBundle mainBundle] URLForResource:@"web-authentication-get-assertion-nfc-multiple-tags" withExtension:@"html" subdirectory:@"TestWebKitAPI.resources"];
+
+ auto *configuration = [WKWebViewConfiguration _test_configurationWithTestPlugInClassName:@"WebProcessPlugInWithInternals" configureJSCForTesting:YES];
+ [[configuration preferences] _setEnabled:YES forExperimentalFeature:webAuthenticationExperimentalFeature()];
+
+ auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:NSZeroRect configuration:configuration]);
+ auto delegate = adoptNS([[TestWebAuthenticationPanelUIDelegate alloc] init]);
+ [webView setUIDelegate:delegate.get()];
+
+ [webView loadRequest:[NSURLRequest requestWithURL:testURL.get()]];
+ Util::run(&webAuthenticationPanelRan);
+ Util::run(&webAuthenticationPanelUpdateMultipleNFCTagsPresent);
+}
+#endif
+
} // namespace TestWebKitAPI
#endif // ENABLE(WEB_AUTHN)
Added: trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/web-authentication-get-assertion-nfc-multiple-tags.html (0 => 251645)
--- trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/web-authentication-get-assertion-nfc-multiple-tags.html (rev 0)
+++ trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/web-authentication-get-assertion-nfc-multiple-tags.html 2019-10-27 22:53:33 UTC (rev 251645)
@@ -0,0 +1,16 @@
+<input type="text" id="input">
+<script>
+ if (window.internals) {
+ internals.setMockWebAuthenticationConfiguration({ silentFailure: true, nfc: { multiplePhysicalTags:true } });
+ internals.withUserGesture(() => { input.focus(); });
+ }
+
+ const options = {
+ publicKey: {
+ challenge: new Uint8Array(16),
+ timeout: 100,
+ }
+ };
+
+ navigator.credentials.get(options);
+</script>