File: policy_data_collector.cc

package info (click to toggle)
chromium 139.0.7258.127-1
  • links: PTS, VCS
  • area: main
  • in suites:
  • size: 6,122,068 kB
  • sloc: cpp: 35,100,771; ansic: 7,163,530; javascript: 4,103,002; python: 1,436,920; asm: 946,517; xml: 746,709; pascal: 187,653; perl: 88,691; sh: 88,436; objc: 79,953; sql: 51,488; cs: 44,583; fortran: 24,137; makefile: 22,147; tcl: 15,277; php: 13,980; yacc: 8,984; ruby: 7,485; awk: 3,720; lisp: 3,096; lex: 1,327; ada: 727; jsp: 228; sed: 36
file content (195 lines) | stat: -rw-r--r-- 8,084 bytes parent folder | download | duplicates (5)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/support_tool/policy_data_collector.h"

#include <map>
#include <optional>
#include <set>
#include <string>
#include <string_view>
#include <utility>

#include "base/containers/fixed_flat_map.h"
#include "base/files/file_path.h"
#include "base/files/file_util.h"
#include "base/json/json_writer.h"
#include "base/memory/scoped_refptr.h"
#include "base/task/sequenced_task_runner.h"
#include "base/task/task_traits.h"
#include "base/task/thread_pool.h"
#include "base/values.h"
#include "build/build_config.h"
#include "chrome/browser/policy/policy_ui_utils.h"
#include "chrome/browser/policy/policy_value_and_status_aggregator.h"
#include "chrome/browser/support_tool/data_collector.h"
#include "components/feedback/redaction_tool/pii_types.h"
#include "components/feedback/redaction_tool/redaction_tool.h"
#include "components/policy/core/browser/webui/json_generation.h"
#include "components/policy/core/browser/webui/policy_status_provider.h"
#include "components/policy/core/browser/webui/policy_webui_constants.h"

#if !BUILDFLAG(IS_CHROMEOS)
#include "components/policy/core/browser/webui/machine_level_user_cloud_policy_status_provider.h"
#endif  // !BUILDFLAG(IS_CHROMEOS)

namespace {

// Returns the PII type that `status_field` is categorised in if it's considered
// as PII.
std::optional<redaction::PIIType> GetPIITypeOfStatusField(
    std::string_view status_field) {
  // List of keys in policy status that will be considered as PII and will be
  // redacted selectively.
  // TODO(crbug.com/41486252): Convert to MakeFixedFlatMap().
  static constexpr auto kPersonallyIdentifiableStatusFields =
      base::MakeFixedFlatMap<std::string_view, redaction::PIIType>({
#if !BUILDFLAG(IS_CHROMEOS)
          {policy::kDeviceIdKey, redaction::PIIType::kStableIdentifier},
          {policy::kEnrollmentTokenKey, redaction::PIIType::kStableIdentifier},
          {policy::kMachineKey, redaction::PIIType::kStableIdentifier},
#endif  // !BUILDFLAG(IS_CHROMEOS)
          {policy::kAssetIdKey, redaction::PIIType::kStableIdentifier},
          // kLocationKey is the "Asset location" which is an identifier for
          // the device that is set during enterprise enrollment or by the
          // administrator.
          {policy::kLocationKey, redaction::PIIType::kStableIdentifier},
          {policy::kDirectoryApiIdKey, redaction::PIIType::kStableIdentifier},
          {policy::kGaiaIdKey, redaction::PIIType::kGaiaID},
          {policy::kClientIdKey, redaction::PIIType::kStableIdentifier},
          {policy::kUsernameKey, redaction::PIIType::kEmail},
          {policy::kEnterpriseDomainManagerKey, redaction::PIIType::kEmail},
          {policy::kDomainKey, redaction::PIIType::kEmail}});
  return kPersonallyIdentifiableStatusFields.contains(status_field)
             ? std::make_optional(
                   kPersonallyIdentifiableStatusFields.at(status_field))
             : std::nullopt;
}

// Opens a file named "policies.json" in `target_directory` and writes
// `policy_data`.
bool WritePolicyData(std::string policy_data, base::FilePath target_directory) {
  base::FilePath target_file =
      target_directory.Append(FILE_PATH_LITERAL("policies.json"));
  return base::WriteFile(target_file, policy_data);
}

}  // namespace

const char kRedactedPlaceholder[] = "REDACTED";

PolicyDataCollector::PolicyDataCollector(Profile* profile) {
  policy_aggregator_ = policy::PolicyValueAndStatusAggregator::
      CreateDefaultPolicyValueAndStatusAggregator(profile);
}

PolicyDataCollector::~PolicyDataCollector() = default;

std::string PolicyDataCollector::GetName() const {
  return "Policies";
}

std::string PolicyDataCollector::GetDescription() const {
  return "Collects available policy values and metadata about policies and "
         "writes it to \"policies.json\" file.";
}

const PIIMap& PolicyDataCollector::GetDetectedPII() {
  return pii_map_;
}

void PolicyDataCollector::CollectDataAndDetectPII(
    DataCollectorDoneCallback on_data_collected_callback,
    scoped_refptr<base::SequencedTaskRunner> task_runner_for_redaction_tool,
    scoped_refptr<redaction::RedactionToolContainer> redaction_tool_container) {
  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);

  policy_values_ = policy_aggregator_->GetAggregatedPolicyValues();
  // `policy_aggregator_` returns the list of policy IDs in
  // policy::kPolicyIdsKey. Remove the list of policy IDs from the output as we
  // don't need it and don't want it to clutter the output.
  policy_values_.Remove(policy::kPolicyIdsKey);

  policy_status_ = policy_aggregator_->GetAggregatedPolicyStatus();
  // Policy values are not expected to contain PII so we only detect the PII in
  // policy status.
  DetectPIIInPolicyStatus();

  std::move(on_data_collected_callback).Run(/*error=*/std::nullopt);
}

void PolicyDataCollector::ExportCollectedDataWithPII(
    std::set<redaction::PIIType> pii_types_to_keep,
    base::FilePath target_directory,
    scoped_refptr<base::SequencedTaskRunner> task_runner_for_redaction_tool,
    scoped_refptr<redaction::RedactionToolContainer> redaction_tool_container,
    DataCollectorDoneCallback on_exported_callback) {
  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);

  // Policy values are not expected to contain PII so we only redact the PII in
  // policy status.
  RedactPIIInPolicyStatus(pii_types_to_keep);

  std::string policy_json = policy::GenerateJson(
      std::move(policy_values_), std::move(policy_status_),
      policy::GetChromeMetadataParams(/*application_name=*/"Support Tool"));

  base::ThreadPool::PostTaskAndReplyWithResult(
      FROM_HERE, {base::MayBlock()},
      base::BindOnce(&WritePolicyData, policy_json, target_directory),
      base::BindOnce(&PolicyDataCollector::OnFileWritten,
                     weak_ptr_factory_.GetWeakPtr(),
                     std::move(on_exported_callback)));
}

void PolicyDataCollector::OnFileWritten(
    DataCollectorDoneCallback on_exported_callback,
    bool success) {
  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  if (!success) {
    SupportToolError error = {SupportToolErrorCode::kDataCollectorError,
                              "PolicyDataCollector failed on data export."};
    std::move(on_exported_callback).Run(error);
    return;
  }
  std::move(on_exported_callback).Run(/*error=*/std::nullopt);
}

void PolicyDataCollector::OnPolicyValueAndStatusChanged() {}

void PolicyDataCollector::DetectPIIInPolicyStatus() {
  for (auto entry : policy_status_) {
    for (const auto [status_key, status_value] : entry.second.GetDict()) {
      std::optional<redaction::PIIType> pii_type =
          GetPIITypeOfStatusField(status_key);
      if (!pii_type)
        continue;
      // A field of policy status can be stored in string or bool. Convert it to
      // string.
      std::string status_value_as_string;
      base::JSONWriter::WriteWithOptions(status_value,
                                         base::JSONWriter::OPTIONS_PRETTY_PRINT,
                                         &status_value_as_string);
      pii_map_[pii_type.value()].insert(status_value_as_string);
    }
  }
}

void PolicyDataCollector::RedactPIIInPolicyStatus(
    std::set<redaction::PIIType> pii_types_to_keep) {
  // Iterator is a reference std::pair<const std::string&, Value&> as explained
  // in base/value_iterators.h documentation.
  for (std::pair<const std::string&, base::Value&> entry : policy_status_) {
    for (std::pair<const std::string&, base::Value&> status_pair :
         entry.second.GetDict()) {
      std::optional<redaction::PIIType> pii_type =
          GetPIITypeOfStatusField(status_pair.first);
      if (!pii_type || base::Contains(pii_types_to_keep, pii_type.value()))
        continue;
      // Replace the value with `kRedactedPlaceholder` if it's a PII type that
      // user didn't select to keep.
      status_pair.second = base::Value(kRedactedPlaceholder);
    }
  }
}