[ios] Implements about:policy.
BUG=1027249
Change-Id: I719bef6dd78c7266ff8eb2f480a34a1effa3f927
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2076448
Commit-Queue: Rohit Rao <[email protected]>
Reviewed-by: Mike Dougherty <[email protected]>
Cr-Commit-Position: refs/heads/master@{#745337}
diff --git a/ios/chrome/browser/ui/webui/BUILD.gn b/ios/chrome/browser/ui/webui/BUILD.gn
index a1e13e0f..8507e22 100644
--- a/ios/chrome/browser/ui/webui/BUILD.gn
+++ b/ios/chrome/browser/ui/webui/BUILD.gn
@@ -103,9 +103,11 @@
"//ios/chrome/browser",
"//ios/chrome/browser/browser_state",
"//ios/chrome/browser/omaha",
+ "//ios/chrome/browser/policy:feature_flags",
"//ios/chrome/browser/signin",
"//ios/chrome/browser/ui/webui/gcm",
"//ios/chrome/browser/ui/webui/net_export",
+ "//ios/chrome/browser/ui/webui/policy",
"//ios/chrome/browser/ui/webui/sync_internals",
"//ios/chrome/browser/ui/webui/translate_internals",
"//url",
diff --git a/ios/chrome/browser/ui/webui/chrome_web_ui_ios_controller_factory.mm b/ios/chrome/browser/ui/webui/chrome_web_ui_ios_controller_factory.mm
index 102d978..a2f30484 100644
--- a/ios/chrome/browser/ui/webui/chrome_web_ui_ios_controller_factory.mm
+++ b/ios/chrome/browser/ui/webui/chrome_web_ui_ios_controller_factory.mm
@@ -9,6 +9,7 @@
#include "base/bind.h"
#include "base/location.h"
#include "ios/chrome/browser/chrome_url_constants.h"
+#include "ios/chrome/browser/policy/policy_features.h"
#include "ios/chrome/browser/system_flags.h"
#include "ios/chrome/browser/ui/webui/about_ui.h"
#include "ios/chrome/browser/ui/webui/autofill_and_password_manager_internals/autofill_internals_ui_ios.h"
@@ -20,6 +21,7 @@
#include "ios/chrome/browser/ui/webui/net_export/net_export_ui.h"
#include "ios/chrome/browser/ui/webui/ntp_tiles_internals_ui.h"
#include "ios/chrome/browser/ui/webui/omaha_ui.h"
+#include "ios/chrome/browser/ui/webui/policy/policy_ui.h"
#include "ios/chrome/browser/ui/webui/prefs_internals_ui.h"
#include "ios/chrome/browser/ui/webui/signin_internals_ui_ios.h"
#include "ios/chrome/browser/ui/webui/suggestions_ui.h"
@@ -109,6 +111,10 @@
if (url_host == kChromeUIVersionHost)
return &NewWebUIIOS<VersionUI>;
+ if (IsEnterprisePolicyEnabled() && url_host == kChromeUIPolicyHost) {
+ return &NewWebUIIOS<PolicyUI>;
+ }
+
return nullptr;
}
diff --git a/ios/chrome/browser/ui/webui/policy/BUILD.gn b/ios/chrome/browser/ui/webui/policy/BUILD.gn
new file mode 100644
index 0000000..cde2d419
--- /dev/null
+++ b/ios/chrome/browser/ui/webui/policy/BUILD.gn
@@ -0,0 +1,28 @@
+# Copyright 2020 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+source_set("policy") {
+ configs += [ "//build/config/compiler:enable_arc" ]
+
+ sources = [
+ "policy_ui.h",
+ "policy_ui.mm",
+ "policy_ui_handler.h",
+ "policy_ui_handler.mm",
+ ]
+
+ deps = [
+ "//base",
+ "//components/policy:generated",
+ "//components/policy/core/browser",
+ "//components/policy/core/common",
+ "//components/resources",
+ "//components/strings",
+ "//ios/chrome/browser:chrome_url_constants",
+ "//ios/chrome/browser/browser_state",
+ "//ios/chrome/browser/policy",
+ "//ios/web/public/webui",
+ "//ui/base",
+ ]
+}
diff --git a/ios/chrome/browser/ui/webui/policy/policy_ui.h b/ios/chrome/browser/ui/webui/policy/policy_ui.h
new file mode 100644
index 0000000..f4c1cb4
--- /dev/null
+++ b/ios/chrome/browser/ui/webui/policy/policy_ui.h
@@ -0,0 +1,23 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef IOS_CHROME_BROWSER_UI_WEBUI_POLICY_POLICY_UI_H_
+#define IOS_CHROME_BROWSER_UI_WEBUI_POLICY_POLICY_UI_H_
+
+#include "ios/web/public/webui/web_ui_ios_controller.h"
+
+namespace web {
+class WebUIIOS;
+}
+
+// The Web UI controller for the chrome://policy page.
+class PolicyUI : public web::WebUIIOSController {
+ public:
+ explicit PolicyUI(web::WebUIIOS* web_ui);
+ ~PolicyUI() override;
+ PolicyUI(const PolicyUI&) = delete;
+ PolicyUI& operator=(const PolicyUI&) = delete;
+};
+
+#endif // IOS_CHROME_BROWSER_UI_WEBUI_POLICY_POLICY_UI_H_
diff --git a/ios/chrome/browser/ui/webui/policy/policy_ui.mm b/ios/chrome/browser/ui/webui/policy/policy_ui.mm
new file mode 100644
index 0000000..14c9b4a
--- /dev/null
+++ b/ios/chrome/browser/ui/webui/policy/policy_ui.mm
@@ -0,0 +1,96 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ios/chrome/browser/ui/webui/policy/policy_ui.h"
+
+#include <memory>
+
+#include "components/grit/dev_ui_components_resources.h"
+#include "components/strings/grit/components_strings.h"
+#include "ios/chrome/browser/browser_state/chrome_browser_state.h"
+#include "ios/chrome/browser/chrome_url_constants.h"
+#include "ios/chrome/browser/ui/webui/policy/policy_ui_handler.h"
+#include "ios/web/public/webui/web_ui_ios.h"
+#include "ios/web/public/webui/web_ui_ios_data_source.h"
+#include "ios/web/public/webui/web_ui_ios_message_handler.h"
+#include "ui/base/webui/web_ui_util.h"
+
+#if !defined(__has_feature) || !__has_feature(objc_arc)
+#error "This file requires ARC support."
+#endif
+
+namespace {
+
+web::WebUIIOSDataSource* CreatePolicyUIHtmlSource() {
+ web::WebUIIOSDataSource* source =
+ web::WebUIIOSDataSource::Create(kChromeUIPolicyHost);
+ PolicyUIHandler::AddCommonLocalizedStringsToSource(source);
+
+ static constexpr webui::LocalizedString kStrings[] = {
+ // Localized strings (alphabetical order).
+ {"exportPoliciesJSON", IDS_EXPORT_POLICIES_JSON},
+ {"filterPlaceholder", IDS_POLICY_FILTER_PLACEHOLDER},
+ {"hideExpandedStatus", IDS_POLICY_HIDE_EXPANDED_STATUS},
+ {"isAffiliatedYes", IDS_POLICY_IS_AFFILIATED_YES},
+ {"isAffiliatedNo", IDS_POLICY_IS_AFFILIATED_NO},
+ {"labelAssetId", IDS_POLICY_LABEL_ASSET_ID},
+ {"labelClientId", IDS_POLICY_LABEL_CLIENT_ID},
+ {"labelDirectoryApiId", IDS_POLICY_LABEL_DIRECTORY_API_ID},
+ {"labelEnterpriseDisplayDomain",
+ IDS_POLICY_LABEL_ENTERPRISE_DISPLAY_DOMAIN},
+ {"labelEnterpriseEnrollmentDomain",
+ IDS_POLICY_LABEL_ENTERPRISE_ENROLLMENT_DOMAIN},
+ {"labelGaiaId", IDS_POLICY_LABEL_GAIA_ID},
+ {"labelIsAffiliated", IDS_POLICY_LABEL_IS_AFFILIATED},
+ {"labelLocation", IDS_POLICY_LABEL_LOCATION},
+ {"labelMachineEnrollmentDomain",
+ IDS_POLICY_LABEL_MACHINE_ENROLLMENT_DOMAIN},
+ {"labelMachineEnrollmentMachineName",
+ IDS_POLICY_LABEL_MACHINE_ENROLLMENT_MACHINE_NAME},
+ {"labelMachineEnrollmentToken",
+ IDS_POLICY_LABEL_MACHINE_ENROLLMENT_TOKEN},
+ {"labelMachineEntrollmentDeviceId",
+ IDS_POLICY_LABEL_MACHINE_ENROLLMENT_DEVICE_ID},
+ {"labelIsOffHoursActive", IDS_POLICY_LABEL_IS_OFFHOURS_ACTIVE},
+ {"labelPoliciesPush", IDS_POLICY_LABEL_PUSH_POLICIES},
+ {"labelRefreshInterval", IDS_POLICY_LABEL_REFRESH_INTERVAL},
+ {"labelStatus", IDS_POLICY_LABEL_STATUS},
+ {"labelTimeSinceLastRefresh", IDS_POLICY_LABEL_TIME_SINCE_LAST_REFRESH},
+ {"labelUsername", IDS_POLICY_LABEL_USERNAME},
+ {"noPoliciesSet", IDS_POLICY_NO_POLICIES_SET},
+ {"offHoursActive", IDS_POLICY_OFFHOURS_ACTIVE},
+ {"offHoursNotActive", IDS_POLICY_OFFHOURS_NOT_ACTIVE},
+ {"policiesPushOff", IDS_POLICY_PUSH_POLICIES_OFF},
+ {"policiesPushOn", IDS_POLICY_PUSH_POLICIES_ON},
+ {"policyLearnMore", IDS_POLICY_LEARN_MORE},
+ {"reloadPolicies", IDS_POLICY_RELOAD_POLICIES},
+ {"showExpandedStatus", IDS_POLICY_SHOW_EXPANDED_STATUS},
+ {"showLess", IDS_POLICY_SHOW_LESS},
+ {"showMore", IDS_POLICY_SHOW_MORE},
+ {"showUnset", IDS_POLICY_SHOW_UNSET},
+ {"signinProfile", IDS_POLICY_SIGNIN_PROFILE},
+ {"status", IDS_POLICY_STATUS},
+ {"statusDevice", IDS_POLICY_STATUS_DEVICE},
+ {"statusMachine", IDS_POLICY_STATUS_MACHINE},
+ {"statusUser", IDS_POLICY_STATUS_USER},
+ };
+ source->AddLocalizedStrings(kStrings);
+ source->UseStringsJs();
+
+ source->AddResourcePath("policy.css", IDR_POLICY_CSS);
+ source->AddResourcePath("policy_base.js", IDR_POLICY_BASE_JS);
+ source->AddResourcePath("policy.js", IDR_POLICY_JS);
+ source->SetDefaultResource(IDR_POLICY_HTML);
+ return source;
+}
+
+} // namespace
+
+PolicyUI::PolicyUI(web::WebUIIOS* web_ui) : web::WebUIIOSController(web_ui) {
+ web_ui->AddMessageHandler(std::make_unique<PolicyUIHandler>());
+ web::WebUIIOSDataSource::Add(ChromeBrowserState::FromWebUIIOS(web_ui),
+ CreatePolicyUIHtmlSource());
+}
+
+PolicyUI::~PolicyUI() {}
diff --git a/ios/chrome/browser/ui/webui/policy/policy_ui_handler.h b/ios/chrome/browser/ui/webui/policy/policy_ui_handler.h
new file mode 100644
index 0000000..2488b0e
--- /dev/null
+++ b/ios/chrome/browser/ui/webui/policy/policy_ui_handler.h
@@ -0,0 +1,74 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef IOS_CHROME_BROWSER_UI_WEBUI_POLICY_POLICY_UI_HANDLER_H_
+#define IOS_CHROME_BROWSER_UI_WEBUI_POLICY_POLICY_UI_HANDLER_H_
+
+#include "base/memory/weak_ptr.h"
+#include "base/values.h"
+#include "components/policy/core/common/policy_service.h"
+#include "components/policy/core/common/schema_registry.h"
+#include "ios/web/public/webui/web_ui_ios.h"
+#include "ios/web/public/webui/web_ui_ios_data_source.h"
+#include "ios/web/public/webui/web_ui_ios_message_handler.h"
+
+namespace policy {
+class PolicyMap;
+struct PolicyNamespace;
+} // namespace policy
+
+// The JavaScript message handler for the chrome://policy page.
+class PolicyUIHandler : public web::WebUIIOSMessageHandler,
+ public policy::PolicyService::Observer,
+ public policy::SchemaRegistry::Observer {
+ public:
+ PolicyUIHandler();
+ ~PolicyUIHandler() override;
+ PolicyUIHandler(const PolicyUIHandler&) = delete;
+ PolicyUIHandler& operator=(const PolicyUIHandler&) = delete;
+
+ static void AddCommonLocalizedStringsToSource(
+ web::WebUIIOSDataSource* source);
+
+ // web::WebUIIOSMessageHandler.
+ void RegisterMessages() override;
+
+ // policy::PolicyService::Observer.
+ void OnPolicyUpdated(const policy::PolicyNamespace& ns,
+ const policy::PolicyMap& previous,
+ const policy::PolicyMap& current) override;
+
+ // policy::SchemaRegistry::Observer.
+ void OnSchemaRegistryUpdated(bool has_new_schemas) override;
+
+ private:
+ // Returns a dictionary containing the policies supported by Chrome.
+ base::Value GetPolicyNames() const;
+
+ // Returns a dictionary containing the current values of the policies
+ // supported by Chrome.
+ base::Value GetPolicyValues() const;
+
+ // Called to handle the "listenPoliciesUpdates" WebUI message.
+ void HandleListenPoliciesUpdates(const base::ListValue* args);
+
+ // Called to handle the "reloadPolicies" WebUI message.
+ void HandleReloadPolicies(const base::ListValue* args);
+
+ // Send information about the current policy values to the UI. For each policy
+ // whose value has been set, dictionaries containing the value and additional
+ // metadata are sent.
+ void SendPolicies();
+
+ // The callback invoked by PolicyService::RefreshPolicies().
+ void OnRefreshPoliciesDone();
+
+ // Returns the PolicyService associated with this WebUI's BrowserState.
+ policy::PolicyService* GetPolicyService() const;
+
+ // Vends WeakPtrs for this object.
+ base::WeakPtrFactory<PolicyUIHandler> weak_factory_{this};
+};
+
+#endif // IOS_CHROME_BROWSER_UI_WEBUI_POLICY_POLICY_UI_HANDLER_H_
diff --git a/ios/chrome/browser/ui/webui/policy/policy_ui_handler.mm b/ios/chrome/browser/ui/webui/policy/policy_ui_handler.mm
new file mode 100644
index 0000000..4fba478
--- /dev/null
+++ b/ios/chrome/browser/ui/webui/policy/policy_ui_handler.mm
@@ -0,0 +1,158 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ios/chrome/browser/ui/webui/policy/policy_ui_handler.h"
+
+#include <utility>
+#include <vector>
+
+#include "base/bind.h"
+#include "base/bind_helpers.h"
+#include "base/callback.h"
+#include "base/values.h"
+#include "components/policy/core/browser/policy_conversions.h"
+#include "components/policy/core/common/policy_map.h"
+#include "components/policy/core/common/policy_types.h"
+#include "components/policy/core/common/schema.h"
+#include "components/policy/core/common/schema_map.h"
+#include "components/policy/policy_constants.h"
+#include "components/strings/grit/components_strings.h"
+#include "ios/chrome/browser/browser_state/chrome_browser_state.h"
+#include "ios/chrome/browser/policy/browser_state_policy_connector.h"
+#include "ios/chrome/browser/policy/policy_conversions_client_ios.h"
+#include "ui/base/webui/web_ui_util.h"
+
+#if !defined(__has_feature) || !__has_feature(objc_arc)
+#error "This file requires ARC support."
+#endif
+
+PolicyUIHandler::PolicyUIHandler() {}
+
+PolicyUIHandler::~PolicyUIHandler() {
+ GetPolicyService()->RemoveObserver(policy::POLICY_DOMAIN_CHROME, this);
+ policy::SchemaRegistry* registry = ChromeBrowserState::FromWebUIIOS(web_ui())
+ ->GetPolicyConnector()
+ ->GetSchemaRegistry();
+ registry->RemoveObserver(this);
+}
+
+void PolicyUIHandler::AddCommonLocalizedStringsToSource(
+ web::WebUIIOSDataSource* source) {
+ static constexpr webui::LocalizedString kStrings[] = {
+ {"conflict", IDS_POLICY_LABEL_CONFLICT},
+ {"headerLevel", IDS_POLICY_HEADER_LEVEL},
+ {"headerName", IDS_POLICY_HEADER_NAME},
+ {"headerScope", IDS_POLICY_HEADER_SCOPE},
+ {"headerSource", IDS_POLICY_HEADER_SOURCE},
+ {"headerStatus", IDS_POLICY_HEADER_STATUS},
+ {"headerValue", IDS_POLICY_HEADER_VALUE},
+ {"warning", IDS_POLICY_HEADER_WARNING},
+ {"levelMandatory", IDS_POLICY_LEVEL_MANDATORY},
+ {"levelRecommended", IDS_POLICY_LEVEL_RECOMMENDED},
+ {"error", IDS_POLICY_LABEL_ERROR},
+ {"ignored", IDS_POLICY_LABEL_IGNORED},
+ {"notSpecified", IDS_POLICY_NOT_SPECIFIED},
+ {"ok", IDS_POLICY_OK},
+ {"scopeDevice", IDS_POLICY_SCOPE_DEVICE},
+ {"scopeUser", IDS_POLICY_SCOPE_USER},
+ {"title", IDS_POLICY_TITLE},
+ {"unknown", IDS_POLICY_UNKNOWN},
+ {"unset", IDS_POLICY_UNSET},
+ {"value", IDS_POLICY_LABEL_VALUE},
+ };
+ source->AddLocalizedStrings(kStrings);
+ source->AddLocalizedStrings(policy::kPolicySources);
+ source->UseStringsJs();
+}
+
+void PolicyUIHandler::RegisterMessages() {
+ GetPolicyService()->AddObserver(policy::POLICY_DOMAIN_CHROME, this);
+
+ ChromeBrowserState* browser_state =
+ ChromeBrowserState::FromWebUIIOS(web_ui());
+ browser_state->GetPolicyConnector()->GetSchemaRegistry()->AddObserver(this);
+
+ web_ui()->RegisterMessageCallback(
+ "listenPoliciesUpdates",
+ base::BindRepeating(&PolicyUIHandler::HandleListenPoliciesUpdates,
+ base::Unretained(this)));
+ web_ui()->RegisterMessageCallback(
+ "reloadPolicies",
+ base::BindRepeating(&PolicyUIHandler::HandleReloadPolicies,
+ base::Unretained(this)));
+}
+
+void PolicyUIHandler::OnSchemaRegistryUpdated(bool has_new_schemas) {
+ // Update UI when new schema is added.
+ if (has_new_schemas) {
+ SendPolicies();
+ }
+}
+
+void PolicyUIHandler::OnPolicyUpdated(const policy::PolicyNamespace& ns,
+ const policy::PolicyMap& previous,
+ const policy::PolicyMap& current) {
+ SendPolicies();
+}
+
+base::Value PolicyUIHandler::GetPolicyNames() const {
+ ChromeBrowserState* browser_state =
+ ChromeBrowserState::FromWebUIIOS(web_ui());
+ policy::SchemaRegistry* registry =
+ browser_state->GetPolicyConnector()->GetSchemaRegistry();
+ scoped_refptr<policy::SchemaMap> schema_map = registry->schema_map();
+
+ // Add Chrome policy names.
+ base::Value chrome_policy_names(base::Value::Type::LIST);
+ policy::PolicyNamespace chrome_namespace(policy::POLICY_DOMAIN_CHROME, "");
+ const policy::Schema* chrome_schema = schema_map->GetSchema(chrome_namespace);
+ for (auto it = chrome_schema->GetPropertiesIterator(); !it.IsAtEnd();
+ it.Advance()) {
+ chrome_policy_names.Append(base::Value(it.key()));
+ }
+
+ base::Value chrome_values(base::Value::Type::DICTIONARY);
+ chrome_values.SetStringKey("name", "Chrome Policies");
+ chrome_values.SetKey("policyNames", std::move(chrome_policy_names));
+
+ base::Value names(base::Value::Type::DICTIONARY);
+ names.SetKey("chrome", std::move(chrome_values));
+ return names;
+}
+
+base::Value PolicyUIHandler::GetPolicyValues() const {
+ auto client = std::make_unique<PolicyConversionsClientIOS>(
+ ChromeBrowserState::FromWebUIIOS(web_ui()));
+ return policy::ArrayPolicyConversions(std::move(client))
+ .EnableConvertValues(true)
+ .ToValue();
+}
+
+void PolicyUIHandler::HandleListenPoliciesUpdates(const base::ListValue* args) {
+ OnRefreshPoliciesDone();
+}
+
+void PolicyUIHandler::HandleReloadPolicies(const base::ListValue* args) {
+ GetPolicyService()->RefreshPolicies(base::Bind(
+ &PolicyUIHandler::OnRefreshPoliciesDone, weak_factory_.GetWeakPtr()));
+}
+
+void PolicyUIHandler::SendPolicies() {
+ base::Value names = GetPolicyNames();
+ base::Value values = GetPolicyValues();
+ std::vector<const base::Value*> args;
+ args.push_back(&names);
+ args.push_back(&values);
+ web_ui()->FireWebUIListener("policies-updated", args);
+}
+
+void PolicyUIHandler::OnRefreshPoliciesDone() {
+ SendPolicies();
+}
+
+policy::PolicyService* PolicyUIHandler::GetPolicyService() const {
+ ChromeBrowserState* browser_state =
+ ChromeBrowserState::FromWebUIIOS(web_ui());
+ return browser_state->GetPolicyConnector()->GetPolicyService();
+}