Index: chrome/browser/chromeos/certificate_provider/certificate_provider_service.cc |
diff --git a/chrome/browser/chromeos/certificate_provider/certificate_provider_service.cc b/chrome/browser/chromeos/certificate_provider/certificate_provider_service.cc |
index 88bd84133790e9cb7c15e4e77ee93b2361155316..a464b3efd5bc2a104707243dfee32d69cc6482fe 100644 |
--- a/chrome/browser/chromeos/certificate_provider/certificate_provider_service.cc |
+++ b/chrome/browser/chromeos/certificate_provider/certificate_provider_service.cc |
@@ -8,6 +8,7 @@ |
#include <utility> |
+#include "ash/shell.h" |
#include "base/bind.h" |
#include "base/bind_helpers.h" |
#include "base/callback.h" |
@@ -17,11 +18,18 @@ |
#include "base/memory/ptr_util.h" |
#include "base/stl_util.h" |
#include "base/strings/string_piece.h" |
+#include "base/strings/utf_string_conversions.h" |
#include "base/task_runner.h" |
#include "base/threading/thread_task_runner_handle.h" |
#include "chrome/browser/chromeos/certificate_provider/certificate_provider.h" |
+#include "chrome/browser/chromeos/login/ui/login_display_host.h" |
+#include "chrome/browser/profiles/profile_manager.h" |
+#include "chrome/browser/ui/browser_finder.h" |
+#include "chrome/browser/ui/browser_window.h" |
#include "net/base/net_errors.h" |
#include "net/ssl/client_key_store.h" |
+#include "ui/views/widget/widget.h" |
+#include "ui/views/window/dialog_client_view.h" |
namespace chromeos { |
@@ -45,6 +53,13 @@ void PostCertificatesToTaskRunner( |
} // namespace |
+// Define timeout for issued sign_request_id. |
+const uint64_t SIGN_REQUEST_ID_TIMEOUT = 10 * 60; // 10 minutes |
+ |
+// The limit of the sign_request_id map size, after which the sanitizing process |
+// will be applied to remove expired entries. |
+const int MAX_SIGN_REQUESTS_MAP_SIZE = 10; |
+ |
class CertificateProviderService::CertKeyProviderImpl |
: public net::ClientKeyStore::CertKeyProvider { |
public: |
@@ -296,8 +311,9 @@ void CertificateProviderService::SSLPrivateKey::DidSignDigest( |
callback.Run(error, signature); |
} |
-CertificateProviderService::CertificateProviderService() |
- : weak_factory_(this) {} |
+CertificateProviderService::CertificateProviderService() : weak_factory_(this) { |
+ AddSignRequestId(123); |
stevenjb
2016/08/09 21:04:38
What is 123? This should be a constant.
igorcov1
2016/08/10 18:05:03
Sorry, I forgot to remove it. It was added to be a
|
+} |
CertificateProviderService::~CertificateProviderService() { |
DCHECK(thread_checker_.CalledOnValidThread()); |
@@ -400,6 +416,148 @@ void CertificateProviderService::OnExtensionUnloaded( |
for (auto callback : sign_requests_.RemoveAllRequests(extension_id)) |
callback.Run(net::ERR_FAILED, std::vector<uint8_t>()); |
+ |
+ last_rejected_[extension_id] = false; |
+} |
+ |
+void CertificateProviderService::OnPinDialogInput( |
+ const std::string& extension_id, |
+ const bool closed) { |
+ last_rejected_[extension_id] = closed; |
+ if (closed) { |
+ active_pin_dialog_ = nullptr; |
stevenjb
2016/08/09 21:04:39
return and elim else
igorcov1
2016/08/10 18:05:03
Done.
|
+ } else { |
+ // Set the temporary callback to be called if user closes the dialog while |
+ // request is processing by the extension. |
+ active_pin_dialog_->SetCallback( |
+ base::Bind(&CertificateProviderService::OnFlowInterrupted, |
+ base::Unretained(this))); |
+ } |
+} |
+ |
+void CertificateProviderService::OnFlowInterrupted( |
+ const base::string16& value) { |
+ DCHECK(value.empty()); |
+ OnPinDialogInput(active_dialog_extension_id_, true); |
+} |
+ |
+bool CertificateProviderService::LastPinDialogClosed( |
+ const std::string& extension_id) { |
+ return last_rejected_[extension_id]; |
+} |
+ |
+bool CertificateProviderService::UpdatePinDialog( |
+ const std::string& extension_id, |
+ const base::string16& error_message, |
+ const bool accept_input, |
+ const RequestPinView::RequestPinCallback& callback) { |
+ if (active_pin_dialog_ == nullptr) { |
+ return false; |
+ } |
+ |
+ if (extension_id != active_dialog_extension_id_ || |
+ !active_pin_dialog_->IsLocked()) { |
+ return false; |
+ } |
+ |
+ active_pin_dialog_->SetCallback(callback); |
+ active_pin_dialog_->SetDialogParameters(error_message, accept_input); |
+ active_pin_dialog_->GetDialogClientView()->UpdateDialogButtons(); |
+ return true; |
+} |
+ |
+RequestPinResponse CertificateProviderService::ShowPinDialog( |
+ const std::string& extension_id, |
+ const std::string& extension_name, |
+ const long long sign_request_id, |
+ const std::string& dialog_type, |
+ const base::string16& error_message, |
+ const bool accept_input, |
+ const RequestPinView::RequestPinCallback& callback) { |
+ // Don't allow the extension to create anything if an active dialog already |
+ // exists. Still if the dialog is there, initiated by the extension then skip |
+ // the signRequestId check as it's possibly expired. |
+ if (active_pin_dialog_ != nullptr) { |
+ if (!active_dialog_extension_id_.empty() && |
+ extension_id == active_dialog_extension_id_ && |
+ active_pin_dialog_->IsLocked()) { |
+ // Set the new callback to be used by the view. |
+ active_pin_dialog_->SetCallback(callback); |
+ active_pin_dialog_->SetDialogParameters(dialog_type, error_message, |
+ accept_input); |
+ active_pin_dialog_->GetDialogClientView()->UpdateDialogButtons(); |
+ return RequestPinResponse::SUCCESS; |
+ } |
+ |
+ return RequestPinResponse::OTHER_FLOW_IN_PROGRESS; |
+ } |
+ |
+ // Check the validity of sign_request_id |
+ if (sign_request_ids_.find(sign_request_id) == sign_request_ids_.end()) { |
+ return RequestPinResponse::INVALID_ID; |
+ } |
+ |
+ struct timeval tv; |
+ int result = gettimeofday(&tv, NULL); |
+ DCHECK_EQ(0, result); |
+ if (tv.tv_sec - sign_request_ids_[sign_request_id] > SIGN_REQUEST_ID_TIMEOUT) |
+ return RequestPinResponse::INVALID_ID; |
+ |
+ active_dialog_extension_id_ = extension_id; |
+ active_pin_dialog_ = new chromeos::RequestPinView( |
+ extension_name, dialog_type, error_message, accept_input, callback); |
+ gfx::NativeWindow context = ash::Shell::GetPrimaryRootWindow(); |
+ if (chromeos::LoginDisplayHost::default_host()) { |
+ active_window_ = views::DialogDelegate::CreateDialogWidget( |
+ active_pin_dialog_, context, |
+ chromeos::LoginDisplayHost::default_host()->GetNativeWindow()); |
+ active_window_->Show(); |
+ } else { |
+ Browser* browser = chrome::FindTabbedBrowser( |
+ ProfileManager::GetPrimaryUserProfile(), true); |
+ if (browser) { |
+ gfx::NativeWindow native_window = browser->window()->GetNativeWindow(); |
+ active_window_ = views::DialogDelegate::CreateDialogWidget( |
+ active_pin_dialog_, context, native_window); |
+ active_window_->Show(); |
+ } |
stevenjb
2016/08/09 21:04:38
Is this still successful if there is no browser?
igorcov1
2016/08/10 18:05:03
Didn't test it yet, but should be. It's the code t
|
+ } |
+ |
+ return RequestPinResponse::SUCCESS; |
+} |
+ |
+bool CertificateProviderService::CloseDialog(const std::string& extension_id) { |
+ if (extension_id != active_dialog_extension_id_ || |
+ active_pin_dialog_ == nullptr) { |
+ LOG(ERROR) << "StopPinRequest called by wrong extension"; |
+ return false; |
+ } |
+ |
+ // Notifying the old callback if present. |
+ active_pin_dialog_->Cancel(); |
+ |
+ // Close the window. |active_pin_dialog_| gets deleted inside Close(). |
+ active_window_->Close(); |
+ active_pin_dialog_ = nullptr; |
+ |
+ return true; |
+} |
+ |
+bool CertificateProviderService::AddSignRequestId( |
+ const uint64_t sign_request_id) { |
+ if (sign_request_ids_[sign_request_id]) { |
+ return false; |
+ } |
+ // Cache the ID with current timestamp. |
+ struct timeval tv; |
+ int result = gettimeofday(&tv, NULL); |
+ DCHECK_EQ(0, result); |
+ sign_request_ids_[sign_request_id] = tv.tv_sec; |
+ if (sign_request_ids_.size() > MAX_SIGN_REQUESTS_MAP_SIZE) { |
+ RemoveExpiredSignRequests(&tv); |
+ } |
+ |
+ return true; |
} |
void CertificateProviderService::GetCertificatesFromExtensions( |
@@ -476,4 +634,14 @@ void CertificateProviderService::RequestSignatureFromExtension( |
} |
} |
+void CertificateProviderService::RemoveExpiredSignRequests(timeval* tv) { |
+ for (auto it = sign_request_ids_.cbegin(); it != sign_request_ids_.cend();) { |
+ if (tv->tv_sec - it->second > SIGN_REQUEST_ID_TIMEOUT) { |
+ sign_request_ids_.erase(it++); |
+ } else { |
+ ++it; |
+ } |
+ } |
+} |
+ |
} // namespace chromeos |