1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "chrome/browser/ui/views/certificate_selector.h"
7 #include <stddef.h> // For size_t.
11 #include "base/logging.h"
12 #include "base/memory/ref_counted.h"
13 #include "base/strings/utf_string_conversions.h"
14 #include "chrome/browser/certificate_viewer.h"
15 #include "chrome/grit/generated_resources.h"
16 #include "components/constrained_window/constrained_window_views.h"
17 #include "components/guest_view/browser/guest_view_base.h"
18 #include "components/web_modal/web_contents_modal_dialog_manager.h"
19 #include "content/public/browser/web_contents.h"
20 #include "ui/base/l10n/l10n_util.h"
21 #include "ui/base/models/table_model.h"
22 #include "ui/base/models/table_model_observer.h"
23 #include "ui/views/controls/button/label_button.h"
24 #include "ui/views/controls/table/table_view.h"
25 #include "ui/views/layout/grid_layout.h"
26 #include "ui/views/layout/layout_constants.h"
27 #include "ui/views/widget/widget.h"
28 #include "ui/views/window/dialog_client_view.h"
30 #if defined(OS_CHROMEOS)
31 #include "chrome/browser/chromeos/certificate_provider/certificate_provider_service.h"
32 #include "chrome/browser/chromeos/certificate_provider/certificate_provider_service_factory.h"
33 #include "extensions/browser/extension_registry.h"
34 #include "extensions/browser/extension_registry_factory.h"
39 const int CertificateSelector::kTableViewWidth
= 400;
40 const int CertificateSelector::kTableViewHeight
= 100;
42 class CertificateSelector::CertificateTableModel
: public ui::TableModel
{
44 // |certs| and |provider_names| must have the same size.
45 CertificateTableModel(const net::CertificateList
& certs
,
46 const std::vector
<std::string
>& provider_names
);
49 int RowCount() override
;
50 base::string16
GetText(int index
, int column_id
) override
;
51 void SetObserver(ui::TableModelObserver
* observer
) override
;
55 base::string16 subject
;
56 base::string16 issuer
;
57 base::string16 provider
;
59 std::vector
<Row
> rows_
;
61 DISALLOW_COPY_AND_ASSIGN(CertificateTableModel
);
64 CertificateSelector::CertificateTableModel::CertificateTableModel(
65 const net::CertificateList
& certs
,
66 const std::vector
<std::string
>& provider_names
) {
67 DCHECK_EQ(certs
.size(), provider_names
.size());
68 for (size_t i
= 0; i
< certs
.size(); i
++) {
69 net::X509Certificate
* cert
= certs
[i
].get();
71 row
.subject
= base::UTF8ToUTF16(cert
->subject().GetDisplayName());
72 row
.issuer
= base::UTF8ToUTF16(cert
->issuer().GetDisplayName());
73 row
.provider
= base::UTF8ToUTF16(provider_names
[i
]);
78 int CertificateSelector::CertificateTableModel::RowCount() {
82 base::string16
CertificateSelector::CertificateTableModel::GetText(
86 DCHECK_LT(static_cast<size_t>(index
), rows_
.size());
88 const Row
& row
= rows_
[index
];
90 case IDS_CERT_SELECTOR_SUBJECT_COLUMN
:
92 case IDS_CERT_SELECTOR_ISSUER_COLUMN
:
94 case IDS_CERT_SELECTOR_PROVIDER_COLUMN
:
99 return base::string16();
102 void CertificateSelector::CertificateTableModel::SetObserver(
103 ui::TableModelObserver
* observer
) {}
105 CertificateSelector::CertificateSelector(
106 const net::CertificateList
& certificates
,
107 content::WebContents
* web_contents
)
108 : web_contents_(web_contents
), table_(nullptr), view_cert_button_(nullptr) {
109 CHECK(web_contents_
);
111 // |provider_names| and |certificates_| are parallel arrays.
112 // The entry at index |i| is the provider name for |certificates_[i]|.
113 std::vector
<std::string
> provider_names
;
114 #if defined(OS_CHROMEOS)
115 chromeos::CertificateProviderService
* service
=
116 chromeos::CertificateProviderServiceFactory::GetForBrowserContext(
117 web_contents
->GetBrowserContext());
118 extensions::ExtensionRegistry
* extension_registry
=
119 extensions::ExtensionRegistryFactory::GetForBrowserContext(
120 web_contents
->GetBrowserContext());
122 for (const auto& cert
: certificates
) {
123 std::string provider_name
;
124 bool has_extension
= false;
125 std::string extension_id
;
126 if (service
->LookUpCertificate(*cert
, &has_extension
, &extension_id
)) {
127 if (!has_extension
) {
128 // This certificate was provided by an extension but isn't provided by
129 // any extension currently. Don't expose it to the user.
132 const auto extension
= extension_registry
->GetExtensionById(
133 extension_id
, extensions::ExtensionRegistry::ENABLED
);
135 // This extension was unloaded in the meantime. Don't show the
139 provider_name
= extension
->short_name();
140 show_provider_column_
= true;
141 } // Otherwise the certificate is provided by the platform.
143 certificates_
.push_back(cert
);
144 provider_names
.push_back(provider_name
);
147 provider_names
.assign(certificates
.size(), std::string());
148 certificates_
= certificates
;
151 model_
.reset(new CertificateTableModel(certificates_
, provider_names
));
154 CertificateSelector::~CertificateSelector() {
155 table_
->SetModel(nullptr);
159 bool CertificateSelector::CanShow(content::WebContents
* web_contents
) {
160 // GetTopLevelWebContents returns |web_contents| if it is not a guest.
161 content::WebContents
* top_level_web_contents
=
162 guest_view::GuestViewBase::GetTopLevelWebContents(web_contents
);
163 return web_modal::WebContentsModalDialogManager::FromWebContents(
164 top_level_web_contents
) != nullptr;
167 void CertificateSelector::Show() {
168 constrained_window::ShowWebModalDialogViews(this, web_contents_
);
170 // Select the first row automatically. This must be done after the dialog has
175 void CertificateSelector::InitWithText(scoped_ptr
<views::View
> text_label
) {
176 views::GridLayout
* const layout
= views::GridLayout::CreatePanel(this);
177 SetLayoutManager(layout
);
179 const int kColumnSetId
= 0;
180 views::ColumnSet
* const column_set
= layout
->AddColumnSet(kColumnSetId
);
181 column_set
->AddColumn(views::GridLayout::FILL
, views::GridLayout::FILL
, 1,
182 views::GridLayout::USE_PREF
, 0, 0);
184 layout
->StartRow(0, kColumnSetId
);
185 layout
->AddView(text_label
.release());
187 layout
->AddPaddingRow(0, views::kRelatedControlVerticalSpacing
);
189 std::vector
<ui::TableColumn
> columns
;
190 columns
.push_back(ui::TableColumn(IDS_CERT_SELECTOR_SUBJECT_COLUMN
,
191 ui::TableColumn::LEFT
, -1, 0.4f
));
192 columns
.push_back(ui::TableColumn(IDS_CERT_SELECTOR_ISSUER_COLUMN
,
193 ui::TableColumn::LEFT
, -1, 0.2f
));
194 if (show_provider_column_
) {
195 columns
.push_back(ui::TableColumn(IDS_CERT_SELECTOR_PROVIDER_COLUMN
,
196 ui::TableColumn::LEFT
, -1, 0.4f
));
198 table_
= new views::TableView(model_
.get(), columns
, views::TEXT_ONLY
,
199 true /* single_selection */);
200 table_
->SetObserver(this);
201 layout
->StartRow(1, kColumnSetId
);
202 layout
->AddView(table_
->CreateParentIfNecessary(), 1, 1,
203 views::GridLayout::FILL
, views::GridLayout::FILL
,
204 kTableViewWidth
, kTableViewHeight
);
206 layout
->AddPaddingRow(0, views::kRelatedControlVerticalSpacing
);
209 net::X509Certificate
* CertificateSelector::GetSelectedCert() const {
210 const int selected
= table_
->FirstSelectedRow();
211 if (selected
< 0) // Nothing is selected in |table_|.
213 CHECK_LT(static_cast<size_t>(selected
), certificates_
.size());
214 return certificates_
[selected
].get();
217 bool CertificateSelector::CanResize() const {
221 base::string16
CertificateSelector::GetWindowTitle() const {
222 return l10n_util::GetStringUTF16(IDS_CLIENT_CERT_DIALOG_TITLE
);
225 bool CertificateSelector::IsDialogButtonEnabled(ui::DialogButton button
) const {
226 return button
!= ui::DIALOG_BUTTON_OK
|| GetSelectedCert() != nullptr;
229 views::View
* CertificateSelector::GetInitiallyFocusedView() {
234 views::View
* CertificateSelector::CreateExtraView() {
235 DCHECK(!view_cert_button_
);
236 scoped_ptr
<views::LabelButton
> button(new views::LabelButton(
237 this, l10n_util::GetStringUTF16(IDS_PAGEINFO_CERT_INFO_BUTTON
)));
238 button
->SetStyle(views::Button::STYLE_BUTTON
);
239 view_cert_button_
= button
.get();
240 return button
.release();
243 ui::ModalType
CertificateSelector::GetModalType() const {
244 return ui::MODAL_TYPE_CHILD
;
247 void CertificateSelector::ButtonPressed(views::Button
* sender
,
248 const ui::Event
& event
) {
249 if (sender
== view_cert_button_
) {
250 net::X509Certificate
* const cert
= GetSelectedCert();
252 ShowCertificateViewer(web_contents_
,
253 web_contents_
->GetTopLevelNativeWindow(), cert
);
257 void CertificateSelector::OnSelectionChanged() {
258 GetDialogClientView()->ok_button()->SetEnabled(GetSelectedCert() != nullptr);
261 void CertificateSelector::OnDoubleClick() {
262 if (GetSelectedCert())
263 GetDialogClientView()->AcceptWindow();
266 } // namespace chrome