summaryrefslogtreecommitdiffstats
path: root/chrome/browser/usb/web_usb_permission_provider.cc
blob: b8f38172e21e2e33b3b9411fba30f55a1687362e (plain)
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
// Copyright 2015 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/usb/web_usb_permission_provider.h"

#include "base/command_line.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/usb/usb_chooser_context.h"
#include "chrome/browser/usb/usb_chooser_context_factory.h"
#include "chrome/common/chrome_switches.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/render_frame_host.h"
#include "content/public/browser/web_contents.h"
#include "device/core/device_client.h"

using content::WebContents;
using device::usb::WebUsbDescriptorSet;
using device::usb::WebUsbConfigurationSubsetPtr;
using device::usb::WebUsbFunctionSubsetPtr;

namespace {

bool FindOriginInDescriptorSet(const WebUsbDescriptorSet* set,
                               const GURL& origin,
                               const uint8_t* configuration_value,
                               const uint8_t* interface_number) {
  if (!set)
    return false;
  for (size_t i = 0; i < set->origins.size(); ++i) {
    if (origin.spec() == set->origins[i])
      return true;
  }
  for (size_t i = 0; i < set->configurations.size(); ++i) {
    const device::usb::WebUsbConfigurationSubsetPtr& config =
        set->configurations[i];
    if (configuration_value &&
        *configuration_value != config->configuration_value)
      continue;
    for (size_t j = 0; i < config->origins.size(); ++j) {
      if (origin.spec() == config->origins[j])
        return true;
    }
    for (size_t j = 0; j < config->functions.size(); ++j) {
      const device::usb::WebUsbFunctionSubsetPtr& function =
          config->functions[j];
      // TODO(reillyg): Implement support for Interface Association Descriptors
      // so that this check will match associated interfaces.
      if (interface_number && *interface_number != function->first_interface)
        continue;
      for (size_t k = 0; k < function->origins.size(); ++k) {
        if (origin.spec() == function->origins[k])
          return true;
      }
    }
  }
  return false;
}

bool EnableWebUsbOnAnyOrigin() {
  return base::CommandLine::ForCurrentProcess()->HasSwitch(
      switches::kEnableWebUsbOnAnyOrigin);
}

}  // namespace

WebUSBPermissionProvider::WebUSBPermissionProvider(
    content::RenderFrameHost* render_frame_host)
    : render_frame_host_(render_frame_host) {
  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
  DCHECK(render_frame_host_);
}

WebUSBPermissionProvider::~WebUSBPermissionProvider() {}

void WebUSBPermissionProvider::HasDevicePermission(
    mojo::Array<device::usb::DeviceInfoPtr> requested_devices,
    const HasDevicePermissionCallback& callback) {
  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
  WebContents* web_contents =
      WebContents::FromRenderFrameHost(render_frame_host_);
  GURL embedding_origin =
      web_contents->GetMainFrame()->GetLastCommittedURL().GetOrigin();
  GURL requesting_origin =
      render_frame_host_->GetLastCommittedURL().GetOrigin();
  Profile* profile =
      Profile::FromBrowserContext(web_contents->GetBrowserContext());
  UsbChooserContext* chooser_context =
      UsbChooserContextFactory::GetForProfile(profile);

  mojo::Array<mojo::String> allowed_guids(0);
  for (size_t i = 0; i < requested_devices.size(); ++i) {
    const device::usb::DeviceInfoPtr& device = requested_devices[i];
    if (FindOriginInDescriptorSet(device->webusb_allowed_origins.get(),
                                  requesting_origin, nullptr, nullptr) &&
        (EnableWebUsbOnAnyOrigin() ||
         chooser_context->HasDevicePermission(requesting_origin,
                                              embedding_origin, device->guid)))
      allowed_guids.push_back(device->guid);
  }
  callback.Run(allowed_guids.Pass());
}

void WebUSBPermissionProvider::HasConfigurationPermission(
    uint8_t requested_configuration_value,
    device::usb::DeviceInfoPtr device,
    const HasInterfacePermissionCallback& callback) {
  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
  callback.Run(FindOriginInDescriptorSet(
      device->webusb_allowed_origins.get(),
      render_frame_host_->GetLastCommittedURL().GetOrigin(),
      &requested_configuration_value, nullptr));
}

void WebUSBPermissionProvider::HasInterfacePermission(
    uint8_t requested_interface,
    uint8_t configuration_value,
    device::usb::DeviceInfoPtr device,
    const HasInterfacePermissionCallback& callback) {
  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
  callback.Run(FindOriginInDescriptorSet(
      device->webusb_allowed_origins.get(),
      render_frame_host_->GetLastCommittedURL().GetOrigin(),
      &configuration_value, &requested_interface));
}

void WebUSBPermissionProvider::Bind(
    mojo::InterfaceRequest<device::usb::PermissionProvider> request) {
  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
  bindings_.AddBinding(this, request.Pass());
}