File: cable_registration_state.h

package info (click to toggle)
chromium 138.0.7204.183-1~deb12u1
  • links: PTS, VCS
  • area: main
  • in suites: bookworm-proposed-updates
  • size: 6,080,960 kB
  • sloc: cpp: 34,937,079; ansic: 7,176,967; javascript: 4,110,704; python: 1,419,954; asm: 946,768; xml: 739,971; pascal: 187,324; sh: 89,623; perl: 88,663; objc: 79,944; sql: 50,304; cs: 41,786; fortran: 24,137; makefile: 21,811; php: 13,980; tcl: 13,166; yacc: 8,925; ruby: 7,485; awk: 3,720; lisp: 3,096; lex: 1,327; ada: 727; jsp: 228; sed: 36
file content (157 lines) | stat: -rw-r--r-- 6,493 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
// Copyright 2023 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef CHROME_BROWSER_WEBAUTHN_ANDROID_CABLE_REGISTRATION_STATE_H_
#define CHROME_BROWSER_WEBAUTHN_ANDROID_CABLE_REGISTRATION_STATE_H_

#include <array>
#include <string>
#include <vector>

#include "base/functional/callback_forward.h"
#include "device/fido/cable/v2_registration.h"
#include "third_party/boringssl/src/include/openssl/base.h"

namespace webauthn::authenticator {

// RegistrationState is a singleton object that holds two FCM registrations when
// required. One registration, the "linking" registration, is used when the user
// links with another device by scanning a QR code. The second is advertised via
// Sync for other devices signed into the same account. The reason for having
// two registrations is that the linking registration can be rotated if the user
// wishes to unlink all QR-linked devices. But we don't want to break synced
// peers when that happens. Instead, for synced peers we require that they have
// received a recent sync status from this device, i.e. we rotate them
// automatically.
class RegistrationState {
 public:
  // SystemInterface abstracts the rest of the system. This is mocked out for
  // tests.
  class SystemInterface {
   public:
    virtual ~SystemInterface();

    // See v2_registration.h to understand this function.
    virtual std::unique_ptr<device::cablev2::authenticator::Registration>
    NewRegistration(
        device::cablev2::authenticator::Registration::Type type,
        base::OnceCallback<void()> on_ready,
        base::RepeatingCallback<
            void(std::unique_ptr<
                 device::cablev2::authenticator::Registration::Event>)>
            event_callback) = 0;

    // Test whether the current device is suitable for prelinking.
    virtual void CanDeviceSupportCable(
        base::OnceCallback<void(bool)> callback) = 0;

    // Test whether the current process is an in Android work profile.
    virtual void AmInWorkProfile(base::OnceCallback<void(bool)> callback) = 0;

    // Fetch prelinking information from Play Services, if any.
    virtual void GetPrelinkFromPlayServices(
        base::OnceCallback<void(std::optional<std::vector<uint8_t>>)>
            callback) = 0;

    // Request that Sync refresh the DeviceInfo entity for this device.
    virtual void RefreshLocalDeviceInfo() = 0;
  };

  explicit RegistrationState(std::unique_ptr<SystemInterface> interface);
  ~RegistrationState();

  void Register();

  bool is_registered_for_linking() const {
    return linking_registration_ != nullptr;
  }
  bool is_registered_for_sync() const { return sync_registration_ != nullptr; }
  device::cablev2::authenticator::Registration* linking_registration() const {
    return linking_registration_.get();
  }
  device::cablev2::authenticator::Registration* sync_registration() const {
    return sync_registration_.get();
  }
  bool device_supports_cable() const { return *device_supports_cable_; }
  bool am_in_work_profile() const { return *am_in_work_profile_; }
  const std::optional<std::vector<uint8_t>>& link_data_from_play_services()
      const {
    DCHECK(have_link_data_from_play_services_);
    return link_data_from_play_services_;
  }

  // have_data_for_sync returns true if this object has loaded enough state to
  // put information into sync's DeviceInfo.
  bool have_data_for_sync() const;

  // Request that this object trigger a DeviceInfo refresh when
  // `have_data_for_sync` is true.
  void SignalSyncWhenReady();

 private:
  bool have_play_services_data() const;
  void QueryPlayServices();
  void OnHavePlayServicesLinkingInformation(
      std::optional<std::vector<uint8_t>> cbor);

  void OnLinkingRegistrationReady();
  void OnSyncRegistrationReady();

  // OnEvent is called when a GCM message is received.
  void OnEvent(
      std::unique_ptr<device::cablev2::authenticator::Registration::Event>
          event);

  void MaybeFlushPendingEvent();

  // MaybeSignalSync prompts the Sync system to refresh local-device data if
  // the Sync data is now ready and |signal_sync_when_ready_| has been set to
  // indicate that the Sync data was not available last time Sync queried it.
  void MaybeSignalSync();

  // OnCanDeviceSupportCable is run with the result of `TestDeviceSupport`.
  void OnDeviceSupportResult(bool result);

  // OnWorkProfileResult is run with the result of `AmInWorkProfile`.
  void OnWorkProfileResult(bool result);

  const std::unique_ptr<SystemInterface> interface_;
  std::unique_ptr<device::cablev2::authenticator::Registration>
      linking_registration_;
  std::unique_ptr<device::cablev2::authenticator::Registration>
      sync_registration_;
  std::unique_ptr<device::cablev2::authenticator::Registration::Event>
      pending_event_;
  // device_supports_cable_ caches the result of a Java function that checks
  // some prerequisites: that the device has Bluetooth and a screenlock. If
  // this value is |nullopt| then its value has not yet been determined.
  //
  // The presence of a screen lock could change but, because of this caching,
  // Clank won't notice in this context until the process restarts. Users can
  // always use a QR code if pre-linking hasn't worked by the time they need
  // it.
  std::optional<bool> device_supports_cable_;
  // am_in_work_profile_ stores whether the current process is in an Android
  // work profile.
  std::optional<bool> am_in_work_profile_;
  // link_data_from_play_services_ contains the response from Play Services, as
  // CBOR-encoded linking information, or `nullopt` if the call was
  // unsuccessful. This field is only meaningful if
  // `have_link_data_from_play_services_` is true.
  std::optional<std::vector<uint8_t>> link_data_from_play_services_;
  // have_link_data_from_play_services_ is true if any call to Play Services has
  // ever completed, successful or not.
  bool have_link_data_from_play_services_ = false;
  // link_data_from_play_services_timeticks_ contains the timestamp when
  // `link_data_from_play_services_` was set.
  base::TimeTicks link_data_from_play_services_timeticks_;
  // play_services_query_pending_ is true if a request to Play Services is
  // currently outstanding.
  bool play_services_query_pending_ = false;
  bool signal_sync_when_ready_ = false;
};

}  // namespace webauthn::authenticator

#endif  // CHROME_BROWSER_WEBAUTHN_ANDROID_CABLE_REGISTRATION_STATE_H_