Use base::Clock in AuthManager for better testing Change-Id: Ifbb23e4da565a1c86ff728803d2e07e3f8c3b1f4 Reviewed-on: https://weave-review.googlesource.com/1873 Reviewed-by: Alex Vakulenko <avakulenko@google.com>
diff --git a/src/component_manager_impl.h b/src/component_manager_impl.h index 426b4b0..6b8ff13 100644 --- a/src/component_manager_impl.h +++ b/src/component_manager_impl.h
@@ -191,6 +191,7 @@ base::DefaultClock default_clock_; base::Clock* clock_{nullptr}; + // An ID of last state change update. Each NotifyPropertiesUpdated() // invocation increments this value by 1. UpdateID last_state_change_id_{0};
diff --git a/src/privet/auth_manager.cc b/src/privet/auth_manager.cc index be7e971..49ef787 100644 --- a/src/privet/auth_manager.cc +++ b/src/privet/auth_manager.cc
@@ -74,8 +74,11 @@ } // namespace AuthManager::AuthManager(const std::vector<uint8_t>& secret, - const std::vector<uint8_t>& certificate_fingerprint) - : secret_{secret}, certificate_fingerprint_{certificate_fingerprint} { + const std::vector<uint8_t>& certificate_fingerprint, + base::Clock* clock) + : clock_{clock ? clock : &default_clock_}, + secret_{secret}, + certificate_fingerprint_{certificate_fingerprint} { if (secret_.size() != kSha256OutputSize) { secret_.resize(kSha256OutputSize); base::RandBytes(secret_.data(), secret_.size()); @@ -85,9 +88,8 @@ AuthManager::~AuthManager() {} // Returns "[hmac]scope:id:time". -std::vector<uint8_t> AuthManager::CreateAccessToken(const UserInfo& user_info, - const base::Time& time) { - std::string data_str{CreateTokenData(user_info, time)}; +std::vector<uint8_t> AuthManager::CreateAccessToken(const UserInfo& user_info) { + std::string data_str{CreateTokenData(user_info, Now())}; std::vector<uint8_t> data{data_str.begin(), data_str.end()}; std::vector<uint8_t> hash{HmacSha256(secret_, data)}; hash.insert(hash.end(), data.begin(), data.end()); @@ -106,11 +108,10 @@ return SplitTokenData(std::string(data.begin(), data.end()), time); } -std::vector<uint8_t> AuthManager::GetRootDeviceToken( - const base::Time& time) const { +std::vector<uint8_t> AuthManager::GetRootDeviceToken() const { Caveat scope{kUwMacaroonCaveatTypeScope, kUwMacaroonCaveatScopeTypeOwner}; Caveat issued{kUwMacaroonCaveatTypeIssued, - static_cast<uint32_t>(time.ToTimeT())}; + static_cast<uint32_t>(Now().ToTimeT())}; UwMacaroonCaveat caveats[] = { scope.GetCaveat(), issued.GetCaveat(), @@ -127,5 +128,9 @@ return token; } +base::Time AuthManager::Now() const { + return clock_->Now(); +} + } // namespace privet } // namespace weave
diff --git a/src/privet/auth_manager.h b/src/privet/auth_manager.h index 8dd6a36..b3a9599 100644 --- a/src/privet/auth_manager.h +++ b/src/privet/auth_manager.h
@@ -8,6 +8,7 @@ #include <string> #include <vector> +#include <base/time/default_clock.h> #include <base/time/time.h> #include <weave/error.h> @@ -19,11 +20,11 @@ class AuthManager { public: AuthManager(const std::vector<uint8_t>& secret, - const std::vector<uint8_t>& certificate_fingerprint); + const std::vector<uint8_t>& certificate_fingerprint, + base::Clock* clock = nullptr); ~AuthManager(); - std::vector<uint8_t> CreateAccessToken(const UserInfo& user_info, - const base::Time& time); + std::vector<uint8_t> CreateAccessToken(const UserInfo& user_info); UserInfo ParseAccessToken(const std::vector<uint8_t>& token, base::Time* time) const; @@ -31,9 +32,14 @@ const std::vector<uint8_t>& GetCertificateFingerprint() const { return certificate_fingerprint_; } - std::vector<uint8_t> GetRootDeviceToken(const base::Time& time) const; + std::vector<uint8_t> GetRootDeviceToken() const; + + base::Time Now() const; private: + base::DefaultClock default_clock_; + base::Clock* clock_{nullptr}; + std::vector<uint8_t> secret_; std::vector<uint8_t> certificate_fingerprint_;
diff --git a/src/privet/auth_manager_unittest.cc b/src/privet/auth_manager_unittest.cc index 3347aa8..4847e01 100644 --- a/src/privet/auth_manager_unittest.cc +++ b/src/privet/auth_manager_unittest.cc
@@ -4,10 +4,14 @@ #include "src/privet/auth_manager.h" +#include <gmock/gmock.h> #include <gtest/gtest.h> #include <weave/settings.h> #include "src/data_encoding.h" +#include "src/test/mock_clock.h" + +using testing::Return; namespace weave { namespace privet { @@ -17,11 +21,12 @@ void SetUp() override { EXPECT_GE(auth_.GetSecret().size(), 32u); EXPECT_GE(auth_.GetCertificateFingerprint().size(), 32u); + + EXPECT_CALL(clock_, Now()) + .WillRepeatedly(Return(base::Time::FromTimeT(1410000000))); } protected: - const base::Time time_ = base::Time::FromTimeT(1410000000); - const std::vector<uint8_t> kSecret{69, 53, 17, 37, 80, 73, 2, 5, 79, 64, 41, 57, 12, 54, 65, 63, 72, 74, 93, 81, 20, 95, 89, 3, 94, 92, 27, 21, 49, 90, 36, 6}; @@ -32,7 +37,8 @@ 22, 47, 23, 77, 42, 98, 96, 25, 83, 16, 9, 14, 91, 44, 15, 75, 60, 62, 10, 18, 82, 35, 88, 100, 30, 45, 7, 46, 67, 84, 58, 85}; - AuthManager auth_{kSecret, kFingerprint}; + test::MockClock clock_; + AuthManager auth_{kSecret, kFingerprint, &clock_}; }; TEST_F(AuthManagerTest, RandomSecret) { @@ -51,77 +57,80 @@ } TEST_F(AuthManagerTest, CreateAccessToken) { - EXPECT_EQ("OUH2L2npY+Gzwjf9AnqigGSK3hxIVR+xX8/Cnu4DGf8wOjA6MTQxMDAwMDAwMA==", - Base64Encode(auth_.CreateAccessToken( - UserInfo{AuthScope::kNone, 123}, time_))); - EXPECT_EQ("iZx0qgEHFF5lq+Q503GtgU0d6gLQ9TlLsU+DcFbZb2QxOjIzNDoxNDEwMDAwMDAw", - Base64Encode(auth_.CreateAccessToken( - UserInfo{AuthScope::kViewer, 234}, time_))); - EXPECT_EQ("qAmlJykiPTnFljfOKSf3BUII9YZG8/ttzD76q+fII1YyOjM0NToxNDEwOTUwNDAw", - Base64Encode(auth_.CreateAccessToken( - UserInfo{AuthScope::kUser, 345}, - time_ + base::TimeDelta::FromDays(11)))); - EXPECT_EQ("fTjecsbwtYj6i8/qPJz900B8EMAjRqU8jLT9kfMoz0czOjQ1NjoxNDEwMDAwMDAw", - Base64Encode(auth_.CreateAccessToken( - UserInfo{AuthScope::kOwner, 456}, time_))); + EXPECT_EQ( + "OUH2L2npY+Gzwjf9AnqigGSK3hxIVR+xX8/Cnu4DGf8wOjA6MTQxMDAwMDAwMA==", + Base64Encode(auth_.CreateAccessToken(UserInfo{AuthScope::kNone, 123}))); + EXPECT_EQ( + "iZx0qgEHFF5lq+Q503GtgU0d6gLQ9TlLsU+DcFbZb2QxOjIzNDoxNDEwMDAwMDAw", + Base64Encode(auth_.CreateAccessToken(UserInfo{AuthScope::kViewer, 234}))); + EXPECT_EQ( + "fTjecsbwtYj6i8/qPJz900B8EMAjRqU8jLT9kfMoz0czOjQ1NjoxNDEwMDAwMDAw", + Base64Encode(auth_.CreateAccessToken(UserInfo{AuthScope::kOwner, 456}))); + EXPECT_CALL(clock_, Now()) + .WillRepeatedly(Return(clock_.Now() + base::TimeDelta::FromDays(11))); + EXPECT_EQ( + "qAmlJykiPTnFljfOKSf3BUII9YZG8/ttzD76q+fII1YyOjM0NToxNDEwOTUwNDAw", + Base64Encode(auth_.CreateAccessToken(UserInfo{AuthScope::kUser, 345}))); } TEST_F(AuthManagerTest, CreateSameToken) { - EXPECT_EQ(auth_.CreateAccessToken(UserInfo{AuthScope::kViewer, 555}, time_), - auth_.CreateAccessToken(UserInfo{AuthScope::kViewer, 555}, time_)); + EXPECT_EQ(auth_.CreateAccessToken(UserInfo{AuthScope::kViewer, 555}), + auth_.CreateAccessToken(UserInfo{AuthScope::kViewer, 555})); } TEST_F(AuthManagerTest, CreateTokenDifferentScope) { - EXPECT_NE(auth_.CreateAccessToken(UserInfo{AuthScope::kViewer, 456}, time_), - auth_.CreateAccessToken(UserInfo{AuthScope::kOwner, 456}, time_)); + EXPECT_NE(auth_.CreateAccessToken(UserInfo{AuthScope::kViewer, 456}), + auth_.CreateAccessToken(UserInfo{AuthScope::kOwner, 456})); } TEST_F(AuthManagerTest, CreateTokenDifferentUser) { - EXPECT_NE(auth_.CreateAccessToken(UserInfo{AuthScope::kOwner, 456}, time_), - auth_.CreateAccessToken(UserInfo{AuthScope::kOwner, 789}, time_)); + EXPECT_NE(auth_.CreateAccessToken(UserInfo{AuthScope::kOwner, 456}), + auth_.CreateAccessToken(UserInfo{AuthScope::kOwner, 789})); } TEST_F(AuthManagerTest, CreateTokenDifferentTime) { - EXPECT_NE(auth_.CreateAccessToken(UserInfo{AuthScope::kOwner, 567}, time_), - auth_.CreateAccessToken(UserInfo{AuthScope::kOwner, 567}, - base::Time::FromTimeT(1400000000))); + auto token = auth_.CreateAccessToken(UserInfo{AuthScope::kOwner, 567}); + EXPECT_CALL(clock_, Now()) + .WillRepeatedly(Return(base::Time::FromTimeT(1400000000))); + EXPECT_NE(token, auth_.CreateAccessToken(UserInfo{AuthScope::kOwner, 567})); } TEST_F(AuthManagerTest, CreateTokenDifferentInstance) { - EXPECT_NE(auth_.CreateAccessToken(UserInfo{AuthScope::kUser, 123}, time_), - AuthManager({}, {}) - .CreateAccessToken(UserInfo{AuthScope::kUser, 123}, time_)); + EXPECT_NE( + auth_.CreateAccessToken(UserInfo{AuthScope::kUser, 123}), + AuthManager({}, {}).CreateAccessToken(UserInfo{AuthScope::kUser, 123})); } TEST_F(AuthManagerTest, ParseAccessToken) { // Multiple attempts with random secrets. for (size_t i = 0; i < 1000; ++i) { - AuthManager auth{{}, {}}; + AuthManager auth{{}, {}, &clock_}; - auto token = auth.CreateAccessToken(UserInfo{AuthScope::kUser, 5}, time_); + auto token = auth.CreateAccessToken(UserInfo{AuthScope::kUser, 5}); base::Time time2; EXPECT_EQ(AuthScope::kUser, auth.ParseAccessToken(token, &time2).scope()); EXPECT_EQ(5u, auth.ParseAccessToken(token, &time2).user_id()); // Token timestamp resolution is one second. - EXPECT_GE(1, std::abs((time_ - time2).InSeconds())); + EXPECT_GE(1, std::abs((clock_.Now() - time2).InSeconds())); } } TEST_F(AuthManagerTest, GetRootDeviceToken) { EXPECT_EQ("UFTBUcgd9d0HnPRnLeroN2mCQgECRgMaVArkgA==", - Base64Encode(auth_.GetRootDeviceToken(time_))); + Base64Encode(auth_.GetRootDeviceToken())); } TEST_F(AuthManagerTest, GetRootDeviceTokenDifferentTime) { + EXPECT_CALL(clock_, Now()) + .WillRepeatedly(Return(clock_.Now() + base::TimeDelta::FromDays(15))); EXPECT_EQ("UGKqwMYGQNOd8jeYFDOsM02CQgECRgMaVB6rAA==", - Base64Encode(auth_.GetRootDeviceToken( - time_ + base::TimeDelta::FromDays(15)))); + Base64Encode(auth_.GetRootDeviceToken())); } TEST_F(AuthManagerTest, GetRootDeviceTokenDifferentSecret) { - AuthManager auth{kSecret2, {}}; + AuthManager auth{kSecret2, {}, &clock_}; EXPECT_EQ("UK1ACOc3cWGjGBoTIX2bd3qCQgECRgMaVArkgA==", - Base64Encode(auth.GetRootDeviceToken(time_))); + Base64Encode(auth.GetRootDeviceToken())); } } // namespace privet
diff --git a/src/privet/mock_delegates.h b/src/privet/mock_delegates.h index 0cfa4ed..5c003a7 100644 --- a/src/privet/mock_delegates.h +++ b/src/privet/mock_delegates.h
@@ -62,8 +62,7 @@ class MockSecurityDelegate : public SecurityDelegate { public: - MOCK_METHOD2(CreateAccessToken, - std::string(const UserInfo&, const base::Time&)); + MOCK_METHOD1(CreateAccessToken, std::string(const UserInfo&)); MOCK_CONST_METHOD2(ParseAccessToken, UserInfo(const std::string&, base::Time*)); MOCK_CONST_METHOD0(GetPairingTypes, std::set<PairingType>()); @@ -81,7 +80,7 @@ MOCK_METHOD2(CancelPairing, bool(const std::string&, ErrorPtr*)); MockSecurityDelegate() { - EXPECT_CALL(*this, CreateAccessToken(_, _)) + EXPECT_CALL(*this, CreateAccessToken(_)) .WillRepeatedly(Return("GuestAccessToken")); EXPECT_CALL(*this, ParseAccessToken(_, _))
diff --git a/src/privet/privet_handler.cc b/src/privet/privet_handler.cc index 0c9887f..b71ea15 100644 --- a/src/privet/privet_handler.cc +++ b/src/privet/privet_handler.cc
@@ -676,10 +676,9 @@ } base::DictionaryValue output; - output.SetString( - kAuthAccessTokenKey, - security_->CreateAccessToken( - UserInfo{requested_auth_scope, ++last_user_id_}, base::Time::Now())); + output.SetString(kAuthAccessTokenKey, + security_->CreateAccessToken( + UserInfo{requested_auth_scope, ++last_user_id_})); output.SetString(kAuthTokenTypeKey, kAuthorizationHeaderPrefix); output.SetInteger(kAuthExpiresInKey, kAccessTokenExpirationSeconds); output.SetString(kAuthScopeKey, EnumToString(requested_auth_scope));
diff --git a/src/privet/privet_handler_unittest.cc b/src/privet/privet_handler_unittest.cc index 13c1999..09146e8 100644 --- a/src/privet/privet_handler_unittest.cc +++ b/src/privet/privet_handler_unittest.cc
@@ -392,7 +392,7 @@ TEST_F(PrivetHandlerTest, AuthPairing) { EXPECT_CALL(security_, IsValidPairingCode("testToken")) .WillRepeatedly(Return(true)); - EXPECT_CALL(security_, CreateAccessToken(_, _)) + EXPECT_CALL(security_, CreateAccessToken(_)) .WillRepeatedly(Return("OwnerAccessToken")); const char kInput[] = R"({ 'mode': 'pairing',
diff --git a/src/privet/security_delegate.h b/src/privet/security_delegate.h index 40f297f..051bf20 100644 --- a/src/privet/security_delegate.h +++ b/src/privet/security_delegate.h
@@ -22,8 +22,7 @@ virtual ~SecurityDelegate() {} // Creates access token for the given scope, user id and |time|. - virtual std::string CreateAccessToken(const UserInfo& user_info, - const base::Time& time) = 0; + virtual std::string CreateAccessToken(const UserInfo& user_info) = 0; // Validates |token| and returns scope and user id parsed from that. virtual UserInfo ParseAccessToken(const std::string& token,
diff --git a/src/privet/security_manager.cc b/src/privet/security_manager.cc index a838dae..00550d1 100644 --- a/src/privet/security_manager.cc +++ b/src/privet/security_manager.cc
@@ -141,9 +141,8 @@ } // Returns "base64([hmac]scope:id:time)". -std::string SecurityManager::CreateAccessToken(const UserInfo& user_info, - const base::Time& time) { - return Base64Encode(auth_manager_->CreateAccessToken(user_info, time)); +std::string SecurityManager::CreateAccessToken(const UserInfo& user_info) { + return Base64Encode(auth_manager_->CreateAccessToken(user_info)); } // Parses "base64([hmac]scope:id:time)". @@ -344,7 +343,7 @@ if (is_security_disabled_) return true; - if (block_pairing_until_ > base::Time::Now()) { + if (block_pairing_until_ > auth_manager_->Now()) { Error::AddTo(error, FROM_HERE, errors::kDomain, errors::kDeviceBusy, "Too many pairing attempts"); return false; @@ -353,7 +352,7 @@ if (++pairing_attemts_ >= kMaxAllowedPairingAttemts) { LOG(INFO) << "Pairing blocked for" << kPairingBlockingTimeMinutes << "minutes."; - block_pairing_until_ = base::Time::Now(); + block_pairing_until_ = auth_manager_->Now(); block_pairing_until_ += base::TimeDelta::FromMinutes(kPairingBlockingTimeMinutes); }
diff --git a/src/privet/security_manager.h b/src/privet/security_manager.h index cab042a..7a3c56a 100644 --- a/src/privet/security_manager.h +++ b/src/privet/security_manager.h
@@ -60,8 +60,7 @@ ~SecurityManager() override; // SecurityDelegate methods - std::string CreateAccessToken(const UserInfo& user_info, - const base::Time& time) override; + std::string CreateAccessToken(const UserInfo& user_info) override; UserInfo ParseAccessToken(const std::string& token, base::Time* time) const override; std::set<PairingType> GetPairingTypes() const override;
diff --git a/src/privet/security_manager_unittest.cc b/src/privet/security_manager_unittest.cc index 6236d78..d9f5c56 100644 --- a/src/privet/security_manager_unittest.cc +++ b/src/privet/security_manager_unittest.cc
@@ -24,10 +24,12 @@ #include "src/data_encoding.h" #include "src/privet/auth_manager.h" #include "src/privet/openssl_utils.h" +#include "src/test/mock_clock.h" #include "third_party/chromium/crypto/p224_spake.h" -using testing::Eq; using testing::_; +using testing::Eq; +using testing::Return; namespace weave { namespace privet { @@ -57,6 +59,11 @@ class SecurityManagerTest : public testing::Test { protected: + void SetUp() override { + EXPECT_CALL(clock_, Now()) + .WillRepeatedly(Return(base::Time::FromTimeT(1410000000))); + } + void PairAndAuthenticate(std::string* fingerprint, std::string* signature) { std::string session_id; std::string device_commitment_base64; @@ -94,13 +101,15 @@ const base::Time time_ = base::Time::FromTimeT(1410000000); provider::test::FakeTaskRunner task_runner_; + test::MockClock clock_; AuthManager auth_manager_{ {}, {{ 59, 47, 77, 247, 129, 187, 188, 158, 172, 105, 246, 93, 102, 83, 8, 138, 176, 141, 37, 63, 223, 40, 153, 121, 134, 23, 120, 106, 24, 205, 7, 135, - }}}; + }}, + &clock_}; SecurityManager security_{&auth_manager_, {PairingType::kEmbeddedCode}, "1234", @@ -109,56 +118,54 @@ }; TEST_F(SecurityManagerTest, IsBase64) { - EXPECT_TRUE(IsBase64( - security_.CreateAccessToken(UserInfo{AuthScope::kUser, 7}, time_))); + EXPECT_TRUE( + IsBase64(security_.CreateAccessToken(UserInfo{AuthScope::kUser, 7}))); } TEST_F(SecurityManagerTest, CreateSameToken) { - EXPECT_EQ( - security_.CreateAccessToken(UserInfo{AuthScope::kViewer, 555}, time_), - security_.CreateAccessToken(UserInfo{AuthScope::kViewer, 555}, time_)); + EXPECT_EQ(security_.CreateAccessToken(UserInfo{AuthScope::kViewer, 555}), + security_.CreateAccessToken(UserInfo{AuthScope::kViewer, 555})); } TEST_F(SecurityManagerTest, CreateTokenDifferentScope) { - EXPECT_NE( - security_.CreateAccessToken(UserInfo{AuthScope::kViewer, 456}, time_), - security_.CreateAccessToken(UserInfo{AuthScope::kOwner, 456}, time_)); + EXPECT_NE(security_.CreateAccessToken(UserInfo{AuthScope::kViewer, 456}), + security_.CreateAccessToken(UserInfo{AuthScope::kOwner, 456})); } TEST_F(SecurityManagerTest, CreateTokenDifferentUser) { - EXPECT_NE( - security_.CreateAccessToken(UserInfo{AuthScope::kOwner, 456}, time_), - security_.CreateAccessToken(UserInfo{AuthScope::kOwner, 789}, time_)); + EXPECT_NE(security_.CreateAccessToken(UserInfo{AuthScope::kOwner, 456}), + security_.CreateAccessToken(UserInfo{AuthScope::kOwner, 789})); } TEST_F(SecurityManagerTest, CreateTokenDifferentTime) { - EXPECT_NE( - security_.CreateAccessToken(UserInfo{AuthScope::kOwner, 567}, time_), - security_.CreateAccessToken(UserInfo{AuthScope::kOwner, 567}, - base::Time::FromTimeT(1400000000))); + auto token = security_.CreateAccessToken(UserInfo{AuthScope::kOwner, 567}); + EXPECT_CALL(clock_, Now()) + .WillRepeatedly(Return(base::Time::FromTimeT(1400000000))); + EXPECT_NE(token, + security_.CreateAccessToken(UserInfo{AuthScope::kOwner, 567})); } TEST_F(SecurityManagerTest, CreateTokenDifferentInstance) { - AuthManager auth{{}, {}}; - EXPECT_NE(security_.CreateAccessToken(UserInfo{AuthScope::kUser, 123}, time_), + AuthManager auth{{}, {}, &clock_}; + EXPECT_NE(security_.CreateAccessToken(UserInfo{AuthScope::kUser, 123}), SecurityManager(&auth, {}, "", false, &task_runner_) - .CreateAccessToken(UserInfo{AuthScope::kUser, 123}, time_)); + .CreateAccessToken(UserInfo{AuthScope::kUser, 123})); } TEST_F(SecurityManagerTest, ParseAccessToken) { // Multiple attempts with random secrets. for (size_t i = 0; i < 1000; ++i) { - AuthManager auth{{}, {}}; + AuthManager auth{{}, {}, &clock_}; SecurityManager security{&auth, {}, "", false, &task_runner_}; std::string token = - security.CreateAccessToken(UserInfo{AuthScope::kUser, 5}, time_); + security.CreateAccessToken(UserInfo{AuthScope::kUser, 5}); base::Time time2; EXPECT_EQ(AuthScope::kUser, security.ParseAccessToken(token, &time2).scope()); EXPECT_EQ(5u, security.ParseAccessToken(token, &time2).user_id()); // Token timestamp resolution is one second. - EXPECT_GE(1, std::abs((time_ - time2).InSeconds())); + EXPECT_GE(1, std::abs((clock_.Now() - time2).InSeconds())); } } @@ -251,13 +258,13 @@ EXPECT_TRUE(pair()); EXPECT_TRUE(pair()); EXPECT_FALSE(pair()); - EXPECT_GT(security_.block_pairing_until_, base::Time::Now()); + EXPECT_GT(security_.block_pairing_until_, clock_.Now()); EXPECT_LE(security_.block_pairing_until_, - base::Time::Now() + base::TimeDelta::FromMinutes(15)); + clock_.Now() + base::TimeDelta::FromMinutes(15)); // Wait timeout. security_.block_pairing_until_ = - base::Time::Now() - base::TimeDelta::FromMinutes(1); + clock_.Now() - base::TimeDelta::FromMinutes(1); // Allow exactly one attempt. EXPECT_TRUE(pair()); @@ -265,7 +272,7 @@ // Wait timeout. security_.block_pairing_until_ = - base::Time::Now() - base::TimeDelta::FromMinutes(1); + clock_.Now() - base::TimeDelta::FromMinutes(1); // Completely unblock by successfully pairing. std::string fingerprint;