Commit 47cd4934 authored by Anton Urusov's avatar Anton Urusov Committed by Commit Bot

Added an initial version of policy-tool page.

This is the initial version of the policy-tool page that is created to make
managing policies easier for admins.

Bug: 
Cq-Include-Trybots: master.tryserver.chromium.linux:closure_compilation
Change-Id: Ia58300dc786a6dabcd14721d134fb52027934739
Reviewed-on: https://chromium-review.googlesource.com/613507Reviewed-by: default avatarJulian Pastarmov <pastarmovj@chromium.org>
Reviewed-by: default avatarTommy Li <tommycli@chromium.org>
Reviewed-by: default avatarOwen Min <zmin@chromium.org>
Reviewed-by: default avatarGeorges Khalil <georgesak@chromium.org>
Commit-Queue: Anton Urusov <urusant@google.com>
Cr-Commit-Position: refs/heads/master@{#502851}
parent f4ed5f0b
......@@ -1997,6 +1997,9 @@ const FeatureEntry kFeatureEntries[] = {
ENABLE_DISABLE_VALUE_TYPE(
message_center::switches::kEnableMessageCenterNewStyleNotification,
message_center::switches::kDisableMessageCenterNewStyleNotification)},
{"enable-policy-tool", flag_descriptions::kEnablePolicyToolName,
flag_descriptions::kEnablePolicyToolDescription, kOsDesktop,
FEATURE_VALUE_TYPE(features::kPolicyTool)},
#endif // !OS_ANDROID
#if defined(OS_CHROMEOS)
{"memory-pressure-thresholds",
......
......@@ -432,6 +432,9 @@
<include name="IDR_POLICY_BASE_JS" file="resources\policy_base.js" type="BINDATA"/>
<include name="IDR_POLICY_JS" file="resources\policy.js" type="BINDATA"/>
<include name="IDR_POLICY_COMMON_CSS" file="resources\policy_common.css" type="BINDATA"/>
<include name="IDR_POLICY_TOOL_HTML" file="resources\policy_tool.html" flattenhtml="true" allowexternalscript="true" type="BINDATA" />
<include name="IDR_POLICY_TOOL_CSS" file="resources\policy_tool.css" type="BINDATA"/>
<include name="IDR_POLICY_TOOL_JS" file="resources\policy_tool.js" type="BINDATA"/>
<if expr="enable_print_preview">
<include name="IDR_PRINT_PREVIEW_HTML" file="resources\print_preview\print_preview.html" flattenhtml="true" allowexternalscript="true" type="BINDATA" />
<include name="IDR_PRINT_PREVIEW_JS" file="resources\print_preview\print_preview.js" flattenhtml="true" type="BINDATA" />
......
......@@ -396,6 +396,11 @@ const char kEnableMaterialDesignFeedbackName[] =
const char kEnableMaterialDesignFeedbackDescription[] =
"If enabled, reporting an issue will load the Material Design feedback UI.";
const char kEnablePolicyToolName[] = "Enable policy management page";
const char kEnablePolicyToolDescription[] =
"If enabled, the chrome://policy-tool URL loads a page for managing "
"policies.";
const char kEnableMidiManagerDynamicInstantiationName[] =
"MIDIManager dynamic instantiation for Web MIDI.";
const char kEnableMidiManagerDynamicInstantiationDescription[] =
......
......@@ -262,6 +262,9 @@ extern const char kEnableMaterialDesignExtensionsDescription[];
extern const char kEnableMaterialDesignFeedbackName[];
extern const char kEnableMaterialDesignFeedbackDescription[];
extern const char kEnablePolicyToolName[];
extern const char kEnablePolicyToolDescription[];
extern const char kEnableMidiManagerDynamicInstantiationName[];
extern const char kEnableMidiManagerDynamicInstantiationDescription[];
......
......@@ -182,6 +182,25 @@ cr.define('policy', function() {
}
},
/*
* Get value width of the value container.
* @param {Object} valueContainer Container for the value.
* @private
*/
getValueWidth_: function(valueContainer) {
return valueContainer.querySelector('.value').offsetWidth;
},
/*
* Update the value width for the value container if necessary.
* @param {Object} valueContainer Container for the value.
* @private
*/
updateValueWidth_: function(valueContainer) {
if (valueContainer.valueWidth == undefined) {
valueContainer.valueWidth = this.getValueWidth_(valueContainer);
}
},
/**
* Check the table columns for overflow. Most columns are automatically
* elided when overflow occurs. The only action required is to add a tooltip
......@@ -201,15 +220,12 @@ cr.define('policy', function() {
// This is required to be able to check whether the contents would still
// overflow the column once it has been hidden and replaced by a link.
var valueContainer = this.querySelector('.value-container');
if (valueContainer.valueWidth == undefined) {
valueContainer.valueWidth =
valueContainer.querySelector('.value').offsetWidth;
}
this.updateValueWidth_(valueContainer);
// Determine whether the contents of the value column overflows. The
// visibility of the contents, replacement link and additional row
// containing the complete value that depend on this are handled by CSS.
if (valueContainer.offsetWidth < valueContainer.valueWidth)
if (valueContainer.offsetWidth <= valueContainer.valueWidth)
this.classList.add('has-overflowed-value');
else
this.classList.remove('has-overflowed-value');
......@@ -532,6 +548,8 @@ cr.define('policy', function() {
return section;
},
tableHeadings: ['Scope', 'Level', 'Source', 'Name', 'Value', 'Status'],
/**
* Creates a new table for displaying policies.
* @return {Element} The newly created table.
......@@ -540,13 +558,12 @@ cr.define('policy', function() {
var newTable = window.document.createElement('table');
var tableHead = window.document.createElement('thead');
var tableRow = window.document.createElement('tr');
var tableHeadings =
['Scope', 'Level', 'Source', 'Name', 'Value', 'Status'];
for (var i = 0; i < tableHeadings.length; i++) {
for (var i = 0; i < this.tableHeadings.length; i++) {
var tableHeader = window.document.createElement('th');
tableHeader.classList.add(tableHeadings[i].toLowerCase() + '-column');
tableHeader.classList.add(
this.tableHeadings[i].toLowerCase() + '-column');
tableHeader.textContent =
loadTimeData.getString('header' + tableHeadings[i]);
loadTimeData.getString('header' + this.tableHeadings[i]);
tableRow.appendChild(tableHeader);
}
tableHead.appendChild(tableRow);
......
/* Copyright (c) 2017 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. */
@import 'policy_common.css';
.edit-button {
float: right;
margin: 0;
padding: 0;
}
tbody:not(.value-editing-on) .value-edit-form {
display: none;
}
tbody.value-editing-on .save-button {
display: block;
float: right;
}
tbody.value-editing-on .edit-button,
tbody.value-editing-on .value {
display: none;
}
<!doctype html>
<html dir="$i18n{textdirection}" lang="$i18n{language}">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, user-scalable=no">
<title>$i18n{title}</title>
<link rel="stylesheet" href="chrome://resources/css/chrome_shared.css">
<link rel="stylesheet" href="uber/uber_shared.css">
<link rel="stylesheet" href="chrome://policy-tool/policy_tool.css">
<script src="chrome://resources/js/action_link.js"></script>
<script src="chrome://resources/js/cr.js"></script>
<script src="chrome://resources/js/cr/ui.js"></script>
<script src="chrome://resources/js/cr/ui/focus_outline_manager.js"></script>
<script src="chrome://resources/js/load_time_data.js"></script>
<script src="chrome://resources/js/util.js"></script>
</head>
<body>
<div id="filter-overlay" class="page">
<header>
<input id="filter" class="search-field-container" type="search"
placeholder="$i18n{filterPlaceholder}"
aria-label="$i18n{filterPlaceholder}" incremental>
</input>
</header>
</div>
<div class="page">
<header>
<h1>$i18n{title}</h1>
</header>
<section class="reload-show-unset-section">
<form id="session-choice">
<input id="session-name-field" type="text" autocomplete="off"
placeholder="$i18n{sessionNamePlaceholder}">
<input type="submit" id="load-session-button"
value="$i18n{loadSession}">
</form>
<div id="show-unset-container" class="show-unset-checkbox">
<label>
<input id="show-unset" type="checkbox"></input>
<span>$i18n{showUnset}</span>
</label>
</div>
</section>
<section id="main-section" class="empty">
<!-- This is where policy tables get dynamically added. -->
</section>
</div>
<div hidden>
<table>
<tbody id="policy-template">
<tr>
<td class="name-column">
<div class="name elide"></div>
</td>
<td class="value-column">
<div class="value-container">
<span class="value"></span>
<a is="action-link" class="toggle-expanded-value"></a>
<button class="edit-button">$i18n{edit}</button>
<form class="value-edit-form">
<input class="value-edit-field" type="text">
<input type="submit" class="save-button"
value="$i18n{save}">
</form>
</div>
</td>
<td class="status-column">
<div class="status elide"></div>
</td>
</tr>
<tr class="expanded-value-container">
<td class="expanded-value" colspan=3></td>
</tr>
</tbody>
</table>
</div>
</body>
<script src="chrome://policy-tool/strings.js"></script>
<script src="chrome://resources/js/i18n_template.js"></script>
<script src="chrome://policy-tool/policy_base.js"></script>
<script src="chrome://policy-tool/policy_tool.js"></script>
</html>
// Copyright 2017 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.
// Override some methods of policy.Page.
/** @override */
policy.Page.setPolicyValues = function(values) {
var page = this.getInstance();
var table = page.policyTables['chrome'];
table.setPolicyValues(values.chromePolicies || {});
if (values.hasOwnProperty('extensionPolicies')) {
for (var extensionId in values.extensionPolicies) {
table = page.policyTables['extension-' + extensionId];
if (table) {
table.setPolicyValues(values.extensionPolicies[extensionId]);
}
}
} else {
for (var extension in page.policyTables) {
if (extension == 'chrome') {
continue;
}
table = page.policyTables[extension];
table.setPolicyValues({});
}
}
};
/** @override */
policy.Page.prototype.initialize = function() {
cr.ui.FocusOutlineManager.forDocument(document);
this.mainSection = $('main-section');
this.policyTables = {};
// Place the initial focus on the session choice input field.
$('session-name-field').select();
$('filter').onsearch = (event) => {
for (policyTable in this.policyTables) {
this.policyTables[policyTable].setFilterPattern($('filter').value);
}
};
$('session-choice').onsubmit = () => {
var session = $('session-name-field').value;
chrome.send('loadSession', [session]);
$('session-name-field').value = '';
// Return false in order to prevent the browser from reloading the whole
// page.
return false;
};
$('show-unset').onchange = () => {
for (policyTable in this.policyTables) {
this.policyTables[policyTable].filter();
}
};
// Notify the browser that the page has loaded, causing it to send the
// list of all known policies and the values from the default session.
chrome.send('initialized');
};
/**
* Extracts current policy values to send to backend for logging.
* @return {Object} The dictionary containing policy values.
*/
policy.Page.prototype.getDictionary = function() {
var result = {chromePolicies: {}, extensionPolicies: {}};
for (var id in this.policyTables) {
if (id == 'chrome') {
result.chromePolicies = this.policyTables[id].getDictionary();
} else {
const PREFIX_LENGTH = 'extension-'.length;
var extensionId = id.substr(PREFIX_LENGTH);
result.extensionPolicies[extensionId] =
this.policyTables[id].getDictionary();
}
}
return result;
};
// Specify necessary columns.
policy.Page.prototype.tableHeadings = ['Name', 'Value', 'Status'];
// Override policy.Policy methods.
/** @override */
policy.Policy.prototype.decorate = function() {
this.updateToggleExpandedValueText_();
this.querySelector('.edit-button')
.addEventListener('click', this.onValueEditing_.bind(this));
this.querySelector('.value-edit-form').onsubmit =
this.submitEditedValue_.bind(this);
this.querySelector('.toggle-expanded-value')
.addEventListener('click', this.toggleExpandedValue_.bind(this));
};
/** @override */
policy.Policy.prototype.initialize = function(name, value, unknown) {
this.name = name;
this.unset = !value;
this.unknown = unknown;
this.querySelector('.name').textContent = name;
if (value) {
this.setValue_(value.value);
}
this.setStatus_(value);
};
/**
* Set the status column.
* @param {Object} value Dictionary with information about the policy value.
* @private
*/
policy.Policy.prototype.setStatus_ = function(value) {
var status;
if (this.unknown) {
status = loadTimeData.getString('unknown');
} else if (!value) {
status = loadTimeData.getString('unset');
} else if (value.error) {
status = value.error;
} else {
status = loadTimeData.getString('ok');
}
this.querySelector('.status').textContent = status;
};
/**
* Set the policy value.
* @param {Object} value Dictionary with information about the policy value.
* @private
*/
policy.Policy.prototype.setValue_ = function(value) {
this.unset = !value;
this.value = value;
this.querySelector('.value').textContent = value || '';
this.querySelector('.expanded-value').textContent = value || '';
this.querySelector('.value-edit-field').value = value || '';
};
/** @override */
policy.Policy.prototype.getValueWidth_ = function(valueContainer) {
return valueContainer.querySelector('.value').offsetWidth +
valueContainer.querySelector('.edit-button').offsetWidth;
};
/**
* Start editing value.
* @private
*/
policy.Policy.prototype.onValueEditing_ = function() {
this.classList.add('value-editing-on');
this.classList.remove('has-overflowed-value');
this.querySelector('.value-edit-field').select();
};
/**
* Update the policy to its new edited value.
* @private
*/
policy.Policy.prototype.submitEditedValue_ = function() {
var newValue = this.querySelector('.value-edit-field').value;
this.setValue_(newValue);
this.setStatus_(newValue);
this.classList.remove('value-editing-on');
this.querySelector('.value-container').valueWidth = undefined;
this.checkOverflow();
var showUnset = $('show-unset').checked;
this.hidden = this.unset && !showUnset ||
this.name.toLowerCase().indexOf(this.parentNode.filterPattern_) == -1;
chrome.send('updateSession', [policy.Page.getInstance().getDictionary()]);
return false;
};
// Override policy.PolicyTable methods.
/**
* Get policy values stored in this table.
* @returns {Object} Dictionary with policy values.
*/
policy.PolicyTable.prototype.getDictionary = function() {
var result = {};
var policies = this.getElementsByTagName('tbody');
for (var i = 0; i < policies.length; i++) {
var policy = policies[i];
if (policy.unset) {
continue;
}
result[policy.name] = {value: policy.value};
}
return result;
};
// Add error showing function.
/**
* Shows an error message to the user.
* @param {String} message_name Identifier for the error message.
*/
policy.showErrorMessage = function(message_name) {
// TODO(urusant): improve error showing.
alert(loadTimeData.getString(message_name));
console.log(loadTimeData.getString(message_name));
};
// Call the main inttialization function when the page finishes loading.
document.addEventListener(
'DOMContentLoaded',
policy.Page.getInstance().initialize.bind(policy.Page.getInstance()));
......@@ -1001,6 +1001,10 @@ split_static_library("ui") {
"webui/plural_string_handler.h",
"webui/policy_indicator_localized_strings_provider.cc",
"webui/policy_indicator_localized_strings_provider.h",
"webui/policy_tool_ui.cc",
"webui/policy_tool_ui.h",
"webui/policy_tool_ui_handler.cc",
"webui/policy_tool_ui_handler.h",
"webui/profile_helper.cc",
"webui/profile_helper.h",
"webui/profile_info_watcher.cc",
......
......@@ -48,6 +48,7 @@
#include "chrome/browser/ui/webui/omnibox/omnibox_ui.h"
#include "chrome/browser/ui/webui/password_manager_internals/password_manager_internals_ui.h"
#include "chrome/browser/ui/webui/physical_web/physical_web_ui.h"
#include "chrome/browser/ui/webui/policy_tool_ui.h"
#include "chrome/browser/ui/webui/policy_ui.h"
#include "chrome/browser/ui/webui/predictors/predictors_ui.h"
#include "chrome/browser/ui/webui/quota_internals/quota_internals_ui.h"
......@@ -548,6 +549,12 @@ WebUIFactoryFunction GetWebUIFactoryFunction(WebUI* web_ui,
if (url.host_piece() == chrome::kChromeUIPolicyHost)
return &NewWebUI<PolicyUI>;
#if !defined(OS_ANDROID)
if (url.host_piece() == chrome::kChromeUIPolicyToolHost &&
PolicyToolUI::IsEnabled()) {
return &NewWebUI<PolicyToolUI>;
}
#endif
#if BUILDFLAG(ENABLE_APP_LIST)
if (url.host_piece() == chrome::kChromeUIAppListStartPageHost)
......
// Copyright 2017 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 "chrome/browser/ui/webui/policy_tool_ui.h"
#include "base/feature_list.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/webui/policy_tool_ui_handler.h"
#include "chrome/common/chrome_features.h"
#include "chrome/common/url_constants.h"
#include "chrome/grit/browser_resources.h"
#include "components/strings/grit/components_strings.h"
namespace {
content::WebUIDataSource* CreatePolicyToolUIHtmlSource() {
content::WebUIDataSource* source =
content::WebUIDataSource::Create(chrome::kChromeUIPolicyToolHost);
PolicyUIHandler::AddCommonLocalizedStringsToSource(source);
source->AddLocalizedString("reloadPolicies", IDS_POLICY_RELOAD_POLICIES);
source->AddLocalizedString("showUnset", IDS_POLICY_SHOW_UNSET);
source->AddLocalizedString("noPoliciesSet", IDS_POLICY_NO_POLICIES_SET);
source->AddLocalizedString("showExpandedValue",
IDS_POLICY_SHOW_EXPANDED_VALUE);
source->AddLocalizedString("hideExpandedValue",
IDS_POLICY_HIDE_EXPANDED_VALUE);
source->AddLocalizedString("loadSession", IDS_POLICY_TOOL_LOAD_SESSION);
source->AddLocalizedString("sessionNamePlaceholder",
IDS_POLICY_TOOL_SESSION_NAME_PLACEHOLDER);
source->AddLocalizedString("filterPlaceholder",
IDS_POLICY_FILTER_PLACEHOLDER);
source->AddLocalizedString("edit", IDS_POLICY_TOOL_EDIT);
source->AddLocalizedString("save", IDS_POLICY_TOOL_SAVE);
source->AddLocalizedString("errorLoggingDisabled",
IDS_POLICY_TOOL_LOGGING_DISABLED);
source->AddLocalizedString("errorInvalidSessionName",
IDS_POLICY_TOOL_INVALID_SESSION_NAME);
source->AddLocalizedString("errorFileCorrupted",
IDS_POLICY_TOOL_CORRUPTED_FILE);
// Overwrite the title value added by PolicyUIHandler.
source->AddLocalizedString("title", IDS_POLICY_TOOL_TITLE);
// Add required resources.
source->AddResourcePath("policy_common.css", IDR_POLICY_COMMON_CSS);
source->AddResourcePath("policy_tool.css", IDR_POLICY_TOOL_CSS);
source->AddResourcePath("policy_base.js", IDR_POLICY_BASE_JS);
source->AddResourcePath("policy_tool.js", IDR_POLICY_TOOL_JS);
source->SetDefaultResource(IDR_POLICY_TOOL_HTML);
return source;
}
} // namespace
PolicyToolUI::PolicyToolUI(content::WebUI* web_ui) : WebUIController(web_ui) {
web_ui->AddMessageHandler(base::MakeUnique<PolicyToolUIHandler>());
content::WebUIDataSource::Add(Profile::FromWebUI(web_ui),
CreatePolicyToolUIHtmlSource());
}
PolicyToolUI::~PolicyToolUI() {}
// static
bool PolicyToolUI::IsEnabled() {
return base::FeatureList::IsEnabled(features::kPolicyTool);
}
// Copyright 2017 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 CHROME_BROWSER_UI_WEBUI_POLICY_TOOL_UI_H_
#define CHROME_BROWSER_UI_WEBUI_POLICY_TOOL_UI_H_
#include "base/macros.h"
#include "content/public/browser/web_ui_controller.h"
namespace content {
class WebUI;
}
// The Web UI controller for the chrome://policy-tool page.
class PolicyToolUI : public content::WebUIController {
public:
explicit PolicyToolUI(content::WebUI* web_ui);
~PolicyToolUI() override;
static bool IsEnabled();
private:
DISALLOW_COPY_AND_ASSIGN(PolicyToolUI);
};
#endif // CHROME_BROWSER_UI_WEBUI_POLICY_TOOL_UI_H_
This diff is collapsed.
// Copyright 2017 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 "chrome/browser/ui/webui/policy_tool_ui_handler.h"
#include "base/files/file_util.h"
#include "base/json/json_reader.h"
#include "base/json/json_writer.h"
#include "base/strings/utf_string_conversions.h"
#include "base/task_scheduler/post_task.h"
#include "build/build_config.h"
#include "chrome/browser/profiles/profile.h"
PolicyToolUIHandler::PolicyToolUIHandler() : callback_weak_ptr_factory_(this) {}
PolicyToolUIHandler::~PolicyToolUIHandler() {}
void PolicyToolUIHandler::RegisterMessages() {
// Set directory for storing sessions.
sessions_dir_ = Profile::FromWebUI(web_ui())->GetPath().Append(
FILE_PATH_LITERAL("Policy sessions"));
// Set current session name.
// TODO(urusant): do so in a smarter way, e.g. choose the last edited session.
session_name_ = FILE_PATH_LITERAL("policy");
web_ui()->RegisterMessageCallback(
"initialized", base::Bind(&PolicyToolUIHandler::HandleInitializedAdmin,
base::Unretained(this)));
web_ui()->RegisterMessageCallback(
"loadSession", base::Bind(&PolicyToolUIHandler::HandleLoadSession,
base::Unretained(this)));
web_ui()->RegisterMessageCallback(
"updateSession", base::Bind(&PolicyToolUIHandler::HandleUpdateSession,
base::Unretained(this)));
}
void PolicyToolUIHandler::OnJavascriptDisallowed() {
callback_weak_ptr_factory_.InvalidateWeakPtrs();
}
base::FilePath PolicyToolUIHandler::GetSessionPath(
const base::FilePath::StringType& name) const {
return sessions_dir_.Append(name).AddExtension(FILE_PATH_LITERAL("json"));
}
std::string PolicyToolUIHandler::ReadOrCreateFileCallback() {
// Create sessions directory, if it doesn't exist yet.
// If unable to create a directory, just silently return a dictionary
// indicating that logging was unsuccessful.
// TODO(urusant): add a possibility to disable logging to disk in similar
// cases.
if (!base::CreateDirectory(sessions_dir_))
return "{\"logged\": false}";
const base::FilePath session_path = GetSessionPath(session_name_);
// Check if the file for the current session already exists. If not, create it
// and put an empty dictionary in it.
base::File session_file(session_path, base::File::Flags::FLAG_CREATE |
base::File::Flags::FLAG_WRITE);
// If unable to open the file, just return an empty dictionary.
if (session_file.created()) {
session_file.WriteAtCurrentPos("{}", 2);
return "{}";
}
session_file.Close();
// Check that the file exists by now. If it doesn't, it means that at least
// one of the filesystem operations wasn't successful. In this case, return
// a dictionary indicating that logging was unsuccessful. Potentially this can
// also be the place to disable logging to disk.
if (!PathExists(session_path)) {
return "{\"logged\": false}";
}
// Read file contents.
std::string contents;
base::ReadFileToString(session_path, &contents);
return contents;
}
void PolicyToolUIHandler::OnFileRead(const std::string& contents) {
std::unique_ptr<base::DictionaryValue> value =
base::DictionaryValue::From(base::JSONReader::Read(contents));
// If contents is not a properly formed JSON string, we alert the user about
// it and send an empty dictionary instead. Note that the broken session file
// would be overrided when the user edits something, so any manual changes
// that made it invalid will be lost.
// TODO(urusant): do it in a smarter way, e.g. revert to a previous session or
// a new session with a generated name.
if (!value) {
value = base::MakeUnique<base::DictionaryValue>();
ShowErrorMessageToUser("errorFileCorrupted");
} else {
bool logged;
if (value->GetBoolean("logged", &logged)) {
if (!logged) {
ShowErrorMessageToUser("errorLoggingDisabled");
}
value->Remove("logged", nullptr);
}
}
CallJavascriptFunction("policy.Page.setPolicyValues", *value);
}
void PolicyToolUIHandler::ImportFile() {
base::PostTaskWithTraitsAndReplyWithResult(
FROM_HERE, {base::MayBlock(), base::TaskPriority::USER_VISIBLE},
base::BindOnce(&PolicyToolUIHandler::ReadOrCreateFileCallback,
base::Unretained(this)),
base::BindOnce(&PolicyToolUIHandler::OnFileRead,
callback_weak_ptr_factory_.GetWeakPtr()));
}
void PolicyToolUIHandler::HandleInitializedAdmin(const base::ListValue* args) {
DCHECK_EQ(0U, args->GetSize());
AllowJavascript();
SendPolicyNames();
ImportFile();
}
bool PolicyToolUIHandler::IsValidSessionName(
const base::FilePath::StringType& name) const {
// Check if the session name is valid, which means that it doesn't use
// filesystem navigation (e.g. ../ or nested folder).
base::FilePath session_path = GetSessionPath(name);
return !session_path.empty() && session_path.DirName() == sessions_dir_;
}
void PolicyToolUIHandler::HandleLoadSession(const base::ListValue* args) {
DCHECK_EQ(1U, args->GetSize());
#if defined(OS_WIN)
base::FilePath::StringType new_session_name =
base::UTF8ToUTF16(args->GetList()[0].GetString());
#else
base::FilePath::StringType new_session_name = args->GetList()[0].GetString();
#endif
if (!IsValidSessionName(new_session_name)) {
ShowErrorMessageToUser("errorInvalidSessionName");
return;
}
session_name_ = new_session_name;
ImportFile();
}
void PolicyToolUIHandler::DoUpdateSession(const std::string& contents) {
if (base::WriteFile(GetSessionPath(session_name_), contents.c_str(),
contents.size()) < static_cast<int>(contents.size())) {
ShowErrorMessageToUser("errorLoggingDisabled");
}
}
void PolicyToolUIHandler::HandleUpdateSession(const base::ListValue* args) {
DCHECK_EQ(1U, args->GetSize());
const base::DictionaryValue* policy_values = nullptr;
args->GetDictionary(0, &policy_values);
DCHECK(policy_values);
std::string converted_values;
base::JSONWriter::Write(*policy_values, &converted_values);
base::PostTaskWithTraits(
FROM_HERE, {base::MayBlock(), base::TaskPriority::BACKGROUND},
base::BindOnce(&PolicyToolUIHandler::DoUpdateSession,
callback_weak_ptr_factory_.GetWeakPtr(),
converted_values));
}
void PolicyToolUIHandler::ShowErrorMessageToUser(
const std::string& message_name) {
CallJavascriptFunction("policy.showErrorMessage", base::Value(message_name));
}
// Copyright 2017 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 CHROME_BROWSER_UI_WEBUI_POLICY_TOOL_UI_HANDLER_H_
#define CHROME_BROWSER_UI_WEBUI_POLICY_TOOL_UI_HANDLER_H_
#include "base/files/file_path.h"
#include "chrome/browser/ui/webui/policy_ui_handler.h"
class PolicyToolUIHandler : public PolicyUIHandler {
public:
PolicyToolUIHandler();
~PolicyToolUIHandler() override;
// content::WebUIMessageHandler implementation.
void RegisterMessages() override;
void OnJavascriptDisallowed() override;
private:
// Reads the current session file (based on the session_name_) and sends the
// contents to the UI.
void ImportFile();
void HandleInitializedAdmin(const base::ListValue* args);
void HandleLoadSession(const base::ListValue* args);
void HandleUpdateSession(const base::ListValue* args);
std::string ReadOrCreateFileCallback();
void OnFileRead(const std::string& contents);
void DoUpdateSession(const std::string& contents);
bool IsValidSessionName(const base::FilePath::StringType& name) const;
void ShowErrorMessageToUser(const std::string& message);
base::FilePath GetSessionPath(const base::FilePath::StringType& name) const;
base::FilePath sessions_dir_;
base::FilePath::StringType session_name_;
base::WeakPtrFactory<PolicyToolUIHandler> callback_weak_ptr_factory_;
DISALLOW_COPY_AND_ASSIGN(PolicyToolUIHandler);
};
#endif // CHROME_BROWSER_UI_WEBUI_POLICY_TOOL_UI_HANDLER_H_
......@@ -342,6 +342,12 @@ const base::Feature kDisablePostScriptPrinting{
"DisablePostScriptPrinting", base::FEATURE_DISABLED_BY_DEFAULT};
#endif
// Enables a page for manaing policies at chrome://policy-tool.
#if !defined(OS_ANDROID)
const base::Feature kPolicyTool{"PolicyTool",
base::FEATURE_DISABLED_BY_DEFAULT};
#endif
#if BUILDFLAG(ENABLE_PLUGINS)
// Prefer HTML content by hiding Flash from the list of plugins.
// https://crbug.com/626728
......
......@@ -177,6 +177,10 @@ extern const base::Feature kPermissionsBlacklist;
extern const base::Feature kDisablePostScriptPrinting;
#endif
#if !defined(OS_ANDROID)
extern const base::Feature kPolicyTool;
#endif
#if BUILDFLAG(ENABLE_PLUGINS)
extern const base::Feature kPreferHtmlOverPlugins;
#endif
......
......@@ -71,6 +71,7 @@ const char kChromeUIInterventionsInternalsURL[] =
"chrome://interventions-internals/";
const char kChromeUIInvalidationsURL[] = "chrome://invalidations/";
const char kChromeUIMemoryInternalsURL[] = "chrome://memory-internals/";
const char kChromeUIPolicyToolURL[] = "chrome://policy-tool";
const char kChromeUINaClURL[] = "chrome://nacl/";
const char kChromeUINetInternalsURL[] = "chrome://net-internals/";
const char kChromeUINewProfileURL[] = "chrome://newprofile/";
......@@ -220,6 +221,7 @@ const char kChromeUIInvalidationsHost[] = "invalidations";
const char kChromeUIKillHost[] = "kill";
const char kChromeUILargeIconHost[] = "large-icon";
const char kChromeUILocalStateHost[] = "local-state";
const char kChromeUIPolicyToolHost[] = "policy-tool";
const char kChromeUIMediaEngagementHost[] = "media-engagement";
const char kChromeUIMemoryInternalsHost[] = "memory-internals";
const char kChromeUINaClHost[] = "nacl";
......
......@@ -62,6 +62,7 @@ extern const char kChromeUIInstantURL[];
extern const char kChromeUIInterstitialURL[];
extern const char kChromeUIInterventionsInternalsURL[];
extern const char kChromeUIInvalidationsURL[];
extern const char kChromeUIPolicyToolURL[];
extern const char kChromeUIMediaEngagementHost[];
extern const char kChromeUIMemoryInternalsURL[];
extern const char kChromeUINaClURL[];
......@@ -208,6 +209,7 @@ extern const char kChromeUIKillHost[];
extern const char kChromeUILargeIconHost[];
extern const char kChromeUILocalStateHost[];
extern const char kChromeUIMemoryInternalsHost[];
extern const char kChromeUIPolicyToolHost[];
extern const char kChromeUINaClHost[];
extern const char kChromeUINetExportHost[];
extern const char kChromeUINetInternalsHost[];
......
......@@ -1575,6 +1575,7 @@ test("browser_tests") {
"../browser/ui/webui/net_internals/net_internals_ui_browsertest.h",
"../browser/ui/webui/ntp/new_tab_ui_browsertest.cc",
"../browser/ui/webui/password_manager_internals/password_manager_internals_ui_browsertest.cc",
"../browser/ui/webui/policy_tool_ui_browsertest.cc",
"../browser/ui/webui/policy_ui_browsertest.cc",
"../browser/ui/webui/prefs_internals_browsertest.cc",
"../browser/ui/webui/print_preview/print_preview_ui_browsertest.cc",
......
......@@ -224,6 +224,31 @@
Unknown policy.
</message>
<!-- chrome://policy-tool -->
<message name="IDS_POLICY_TOOL_TITLE" desc="Admin page title and the title of the section that lists policies.">
Policy management
</message>
<message name="IDS_POLICY_TOOL_EDIT" desc="Label for the button to change policy value in current session.">
Edit
</message>
<message name="IDS_POLICY_TOOL_SAVE" desc="Label for the button to save policy value after editing it.">
Save
</message>
<message name="IDS_POLICY_TOOL_LOAD_SESSION" desc="Label for the button that loads specified session.">
Load session
</message>
<message name="IDS_POLICY_TOOL_SESSION_NAME_PLACEHOLDER" desc="Placeholder for the input field that lets the user change policy management sessions.">
Session name
</message>
<message name="IDS_POLICY_TOOL_LOGGING_DISABLED" desc="A message that is shown to the user when there is some problem that prevents saving the current policy editing session to disk.">
There seems to be a problem. Saving the session to disk might not work properly.
</message>
<message name="IDS_POLICY_TOOL_INVALID_SESSION_NAME" desc="A message that is shown to the user when the entered session name is invalid.">
Please enter a valid session name.
</message>
<message name="IDS_POLICY_TOOL_CORRUPTED_FILE" desc="A message that is shown to the user when the session file is corrupted">
The session file is corrupted. Please load another session or create a new one.
</message>
<!-- chrome://policy -->
<message name="IDS_POLICY_TITLE" desc="Page title and the title of the section that lists policies.">
Policies
......
......@@ -24023,6 +24023,7 @@ from previous Chrome versions.
<int value="716080990" label="restrict-iframe-permissions"/>
<int value="719267310"
label="KeepAliveRendererForKeepaliveRequests:disabled"/>
<int value="721225492" label="PolicyTool:enabled"/>
<int value="724208771" label="TabsInCBD:enabled"/>
<int value="730024226" label="enable-out-of-process-pdf"/>
<int value="730750097" label="PermissionsBlacklist:disabled"/>
......@@ -24141,6 +24142,7 @@ from previous Chrome versions.
<int value="1108663108" label="disable-device-discovery-notifications"/>
<int value="1113365156" label="tab-management-experiment-type-chive"/>
<int value="1114629582" label="enable-floating-virtual-keyboard"/>
<int value="1115476442" label="PolicyTool:disabled"/>
<int value="1116593018" label="CaptureThumbnailOnLoadFinished:disabled"/>
<int value="1118109174" label="enable-launcher-search-provider-api"/>
<int value="1126061778" label="CaptureThumbnailOnLoadFinished:enabled"/>
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment