File: usb_policy_allowed_devices.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 (139 lines) | stat: -rw-r--r-- 5,506 bytes parent folder | download | duplicates (6)
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
// Copyright 2018 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/usb/usb_policy_allowed_devices.h"

#include <optional>
#include <string>
#include <vector>

#include "base/check_deref.h"
#include "base/functional/bind.h"
#include "base/strings/string_split.h"
#include "base/values.h"
#include "components/content_settings/core/common/pref_names.h"
#include "components/prefs/pref_service.h"
#include "services/device/public/mojom/usb_device.mojom.h"
#include "services/device/public/mojom/usb_manager.mojom.h"
#include "url/gurl.h"

namespace {

constexpr char kPrefDevicesKey[] = "devices";
constexpr char kPrefUrlsKey[] = "urls";
constexpr char kPrefVendorIdKey[] = "vendor_id";
constexpr char kPrefProductIdKey[] = "product_id";

}  // namespace

UsbPolicyAllowedDevices::UsbPolicyAllowedDevices(PrefService* pref_service) {
  pref_change_registrar_.Init(pref_service);
  // Add an observer for |kManagedWebUsbAllowDevicesForUrls| to call
  // CreateOrUpdateMap when the value is changed. The lifetime of
  // |pref_change_registrar_| is managed by this class, therefore it is safe to
  // use base::Unretained here.
  pref_change_registrar_.Add(
      prefs::kManagedWebUsbAllowDevicesForUrls,
      base::BindRepeating(&UsbPolicyAllowedDevices::CreateOrUpdateMap,
                          base::Unretained(this)));

  CreateOrUpdateMap();
}

UsbPolicyAllowedDevices::~UsbPolicyAllowedDevices() = default;

bool UsbPolicyAllowedDevices::IsDeviceAllowed(
    const url::Origin& origin,
    const device::mojom::UsbDeviceInfo& device_info) const {
  return IsDeviceAllowed(
      origin, std::make_pair(device_info.vendor_id, device_info.product_id));
}

bool UsbPolicyAllowedDevices::IsDeviceAllowed(
    const url::Origin& origin,
    const std::pair<int, int>& device_ids) const {
  // Search through each set of URL pair that match the given device. The
  // keys correspond to the following URL pair sets:
  //  * (vendor_id, product_id): A set corresponding to the exact device.
  //  * (vendor_id, -1): A set corresponding to any device with |vendor_id|.
  //  * (-1, -1): A set corresponding to any device.
  const std::pair<int, int> set_keys[] = {
      std::make_pair(device_ids.first, device_ids.second),
      std::make_pair(device_ids.first, -1), std::make_pair(-1, -1)};

  for (const auto& key : set_keys) {
    const auto entry = usb_device_ids_to_urls_.find(key);
    if (entry == usb_device_ids_to_urls_.cend())
      continue;

    if (entry->second.find(origin) != entry->second.end())
      return true;
  }
  return false;
}

void UsbPolicyAllowedDevices::CreateOrUpdateMap() {
  const base::Value::List& pref_list = pref_change_registrar_.prefs()->GetList(
      prefs::kManagedWebUsbAllowDevicesForUrls);
  usb_device_ids_to_urls_.clear();

  // The pref value has already been validated by the policy handler, so it is
  // safe to assume that |pref_list| follows the policy template.
  for (const base::Value& item_val : pref_list) {
    const base::Value::Dict& item = item_val.GetDict();
    const base::Value::List* urls_list = item.FindList(kPrefUrlsKey);
    std::set<url::Origin> parsed_set;

    // A urls item can contain a pair of URLs that are delimited by a comma. If
    // it does not contain a second URL, set the embedding URL to an empty GURL
    // to signify a wildcard embedded URL.
    for (const auto& urls_value : CHECK_DEREF(urls_list)) {
      std::vector<std::string> urls =
          base::SplitString(urls_value.GetString(), ",", base::TRIM_WHITESPACE,
                            base::SPLIT_WANT_ALL);

      // Skip invalid URL entries.
      if (urls.empty())
        continue;

      auto requesting_origin = url::Origin::Create(GURL(urls[0]));
      std::optional<url::Origin> embedding_origin;
      if (urls.size() == 2 && !urls[1].empty())
        embedding_origin = url::Origin::Create(GURL(urls[1]));

      // In order to be compatible with legacy (requesting,embedding) entries
      // without breaking any access specified, we will grant the permission to
      // the embedder if present because under permission delegation the
      // top-level origin has the permission. If only the requesting origin is
      // present, use that instead.
      auto origin = embedding_origin.has_value() ? embedding_origin.value()
                                                 : requesting_origin;

      parsed_set.insert(std::move(origin));
    }

    // Ignore items with empty parsed URLs.
    if (parsed_set.empty())
      continue;

    // For each device entry in the map, create or update its respective URL
    // set.
    const base::Value::List* devices = item.FindList(kPrefDevicesKey);
    for (const base::Value& device_val : CHECK_DEREF(devices)) {
      const base::Value::Dict& device = device_val.GetDict();
      // A missing ID signifies a wildcard for that ID, so a sentinel value of
      // -1 is assigned.
      const std::optional<int> vendor_id_optional =
          device.FindInt(kPrefVendorIdKey);
      const std::optional<int> product_id_optional =
          device.FindInt(kPrefProductIdKey);
      int vendor_id = vendor_id_optional.value_or(-1);
      int product_id = product_id_optional.value_or(-1);
      DCHECK(vendor_id != -1 || product_id == -1);

      auto key = std::make_pair(vendor_id, product_id);
      usb_device_ids_to_urls_[key].insert(parsed_set.begin(), parsed_set.end());
    }
  }
}