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
  196
  197
  198
  199
  200
  201
  202
  203
  204
  205
  206
  207
  208
  209
  210
  211
  212
  213
  214
  215
  216
  217
  218
  219
  220
  221
  222
  223
  224
  225
  226
  227
  228
  229
  230

content / public / browser / bluetooth_delegate.h [blame]

// Copyright 2020 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef CONTENT_PUBLIC_BROWSER_BLUETOOTH_DELEGATE_H_
#define CONTENT_PUBLIC_BROWSER_BLUETOOTH_DELEGATE_H_

#include <string>
#include <vector>

#include "base/observer_list_types.h"
#include "base/scoped_observation_traits.h"
#include "build/build_config.h"
#include "content/common/content_export.h"
#include "content/public/browser/bluetooth_chooser.h"
#include "content/public/browser/bluetooth_scanning_prompt.h"
#include "third_party/blink/public/mojom/bluetooth/web_bluetooth.mojom-forward.h"
#include "url/origin.h"

// Some OS Bluetooth stacks (macOS and Android) automatically bond to a device
// when accessing a characteristic/descriptor which requires an authenticated
// client. For other platforms Chrome does the on-demand pairing.
#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_LINUX)
#define PAIR_BLUETOOTH_ON_DEMAND() true
#else
#define PAIR_BLUETOOTH_ON_DEMAND() false
#endif

namespace blink {
class WebBluetoothDeviceId;
}  // namespace blink

namespace device {
class BluetoothDevice;
class BluetoothUUID;
}  // namespace device

namespace content {

class RenderFrameHost;

// Provides an interface for managing device permissions for Web Bluetooth and
// Web Bluetooth Scanning API. An embedder may implement this to manage these
// permissions.
// TODO(crbug.com/40117221): There are several Bluetooth related methods
// in WebContentsDelegate and ContentBrowserClient that can be moved into this
// class.
class CONTENT_EXPORT BluetoothDelegate {
 public:
  // The result of the prompt when requesting device pairing
  // from the user.
  enum class PairPromptStatus {
    kSuccess,    // Result contains user credentials.
    kCancelled,  // User cancelled, or agent cancelled on their behalf.
  };

  // Based on the pairing kinds defined by Windows but it also applies to any
  // platform on which we support manual pairing through |PairingDelegate| Ref:
  // https://docs.microsoft.com/en-us/uwp/api/windows.devices.enumeration.devicepairingkinds?view=winrt-22621
  enum class PairingKind {
    kConfirmOnly,
    kConfirmPinMatch,
    kDisplayPin,
    kProvidePasswordCredential,
    kProvidePin
  };

  // Struct for pairing prompt result, include |pairing_kind| or |pin| or other
  // needed fields added in future all other fieds should be meaniningful only
  // if |result_code| is |kSuccess|
  struct PairPromptResult {
    PairPromptResult() = default;
    explicit PairPromptResult(PairPromptStatus code) : result_code(code) {}
    ~PairPromptResult() = default;

    PairPromptStatus result_code = PairPromptStatus::kCancelled;
    std::string pin;
  };

  using PairPromptCallback =
      base::OnceCallback<void(const PairPromptResult& result)>;

  // An observer used to track permission revocation events for a particular
  // RenderFrameHost.
  class CONTENT_EXPORT FramePermissionObserver : public base::CheckedObserver {
   public:
    // Notify observer that an object permission was revoked for |origin|.
    virtual void OnPermissionRevoked(const url::Origin& origin) = 0;

    // Returns the frame that the observer wishes to watch.
    virtual RenderFrameHost* GetRenderFrameHost() = 0;
  };
  virtual ~BluetoothDelegate() = default;

  // Shows a chooser for the user to select a nearby Bluetooth device. The
  // EventHandler should live at least as long as the returned chooser object.
  virtual std::unique_ptr<BluetoothChooser> RunBluetoothChooser(
      RenderFrameHost* frame,
      const BluetoothChooser::EventHandler& event_handler) = 0;

  // Shows a prompt for the user to allow/block Bluetooth scanning. The
  // EventHandler should live at least as long as the returned prompt object.
  virtual std::unique_ptr<BluetoothScanningPrompt> ShowBluetoothScanningPrompt(
      RenderFrameHost* frame,
      const BluetoothScanningPrompt::EventHandler& event_handler) = 0;

  // Prompt the user (via dialog, etc.) for pairing Bluetooth device
  // |device_identifier| is any string the caller wants to display
  // to the user to identify the device (MAC address, name, etc.). |callback|
  // will be called with the prompt result. |callback| may be called immediately
  // from this function, for example, if a credential prompt for the given
  // |frame| is already displayed.
  // |pairing_kind| is to determine which pairing kind of prompt to be created
  virtual void ShowDevicePairPrompt(
      RenderFrameHost* frame,
      const std::u16string& device_identifier,
      PairPromptCallback callback,
      PairingKind pairing_kind,
      const std::optional<std::u16string>& pin) = 0;

  // This should return the WebBluetoothDeviceId that corresponds to the device
  // with |device_address| in the current |frame|. If there is not a
  // corresponding ID, then an invalid WebBluetoothDeviceId should be returned.
  virtual blink::WebBluetoothDeviceId GetWebBluetoothDeviceId(
      RenderFrameHost* frame,
      const std::string& device_address) = 0;

  // This should return the device address corresponding to a device with
  // |device_id| in the current |frame|. If there is not a corresponding
  // address, then an empty string should be returned.
  virtual std::string GetDeviceAddress(
      RenderFrameHost* frame,
      const blink::WebBluetoothDeviceId& device_id) = 0;

  // This should return the WebBluetoothDeviceId for |device_address| if the
  // device has been assigned an ID previously through AddScannedDevice() or
  // GrantServiceAccessPermission(). If not, a new ID should be generated for
  // |device_address| and stored in a temporary map of address to ID. Service
  // access should not be granted to these devices.
  virtual blink::WebBluetoothDeviceId AddScannedDevice(
      RenderFrameHost* frame,
      const std::string& device_address) = 0;

  // This should grant permission to the requesting and embedding origins
  // represented by |frame| to connect to the device with |device_address| and
  // access its |services|. Once permission is granted, a |WebBluetoothDeviceId|
  // should be generated for the device and returned.
  virtual blink::WebBluetoothDeviceId GrantServiceAccessPermission(
      RenderFrameHost* frame,
      const device::BluetoothDevice* device,
      const blink::mojom::WebBluetoothRequestDeviceOptions* options) = 0;

  // This should return true if |frame| has been granted permission to access
  // the device with |device_id| through GrantServiceAccessPermission().
  // |device_id|s generated with AddScannedDevices() should return false.
  virtual bool HasDevicePermission(
      RenderFrameHost* frame,
      const blink::WebBluetoothDeviceId& device_id) = 0;

  // Revokes |frame| access to the Bluetooth device ordered by website.
  virtual void RevokeDevicePermissionWebInitiated(
      RenderFrameHost* frame,
      const blink::WebBluetoothDeviceId& device_id) = 0;

  // This should return true if |frame| is allowed to use bluetooth.
  virtual bool MayUseBluetooth(RenderFrameHost* frame) = 0;

  // This should return true if |frame| has permission to access |service| from
  // the device with |device_id|.
  virtual bool IsAllowedToAccessService(
      RenderFrameHost* frame,
      const blink::WebBluetoothDeviceId& device_id,
      const device::BluetoothUUID& service) = 0;

  // This should return true if |frame| can access at least one service from the
  // device with |device_id|.
  virtual bool IsAllowedToAccessAtLeastOneService(
      RenderFrameHost* frame,
      const blink::WebBluetoothDeviceId& device_id) = 0;

  // This should return true if |frame| has permission to access data associated
  // with |manufacturer_code| from advertisement packets from the device with
  // |device_id|.
  virtual bool IsAllowedToAccessManufacturerData(
      RenderFrameHost* frame,
      const blink::WebBluetoothDeviceId& device_id,
      uint16_t manufacturer_code) = 0;

  // This should return a list of devices that the origin in |frame| has been
  // allowed to access. Access permission is granted with
  // GrantServiceAccessPermission() and can be revoked by the user in the
  // embedder's UI. The list of devices returned should be PermittedDevice
  // objects, which contain the necessary fields to create the BluetoothDevice
  // JavaScript objects.
  virtual std::vector<blink::mojom::WebBluetoothDevicePtr> GetPermittedDevices(
      RenderFrameHost* frame) = 0;

  // Add a permission observer to allow observing permission revocation effects
  // for a particular frame.
  virtual void AddFramePermissionObserver(
      FramePermissionObserver* observer) = 0;

  // Remove a previously added permission observer.
  virtual void RemoveFramePermissionObserver(
      FramePermissionObserver* observer) = 0;
};

}  // namespace content

namespace base {

template <>
struct ScopedObservationTraits<
    content::BluetoothDelegate,
    content::BluetoothDelegate::FramePermissionObserver> {
  static void AddObserver(
      content::BluetoothDelegate* source,
      content::BluetoothDelegate::FramePermissionObserver* observer) {
    source->AddFramePermissionObserver(observer);
  }
  static void RemoveObserver(
      content::BluetoothDelegate* source,
      content::BluetoothDelegate::FramePermissionObserver* observer) {
    source->RemoveFramePermissionObserver(observer);
  }
};

}  // namespace base

#endif  // CONTENT_PUBLIC_BROWSER_BLUETOOTH_DELEGATE_H_