tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

MediaKeys.h (9223B)


      1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
      2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
      3 /* This Source Code Form is subject to the terms of the Mozilla Public
      4 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
      5 * You can obtain one at http://mozilla.org/MPL/2.0/. */
      6 
      7 #ifndef mozilla_dom_mediakeys_h__
      8 #define mozilla_dom_mediakeys_h__
      9 
     10 #include "DecoderDoctorLogger.h"
     11 #include "mozilla/DetailedPromise.h"
     12 #include "mozilla/RefPtr.h"
     13 #include "mozilla/WeakPtr.h"
     14 #include "mozilla/dom/MediaKeyStatusMapBinding.h"  // For MediaKeyStatus
     15 #include "mozilla/dom/MediaKeySystemAccessBinding.h"
     16 #include "mozilla/dom/MediaKeysBinding.h"
     17 #include "mozilla/dom/Promise.h"
     18 #include "nsCOMPtr.h"
     19 #include "nsCycleCollectionParticipant.h"
     20 #include "nsIObserver.h"
     21 #include "nsRefPtrHashtable.h"
     22 #include "nsTHashMap.h"
     23 #include "nsWrapperCache.h"
     24 
     25 namespace mozilla {
     26 
     27 class CDMProxy;
     28 
     29 namespace dom {
     30 class MediaKeys;
     31 }  // namespace dom
     32 DDLoggedTypeName(dom::MediaKeys);
     33 
     34 namespace dom {
     35 
     36 class ArrayBufferViewOrArrayBuffer;
     37 class MediaKeySession;
     38 struct MediaKeysPolicy;
     39 class HTMLMediaElement;
     40 
     41 typedef nsRefPtrHashtable<nsStringHashKey, MediaKeySession> KeySessionHashMap;
     42 typedef nsRefPtrHashtable<nsUint32HashKey, dom::DetailedPromise> PromiseHashMap;
     43 typedef nsRefPtrHashtable<nsUint32HashKey, MediaKeySession>
     44    PendingKeySessionsHashMap;
     45 typedef nsTHashMap<nsUint32HashKey, uint32_t> PendingPromiseIdTokenHashMap;
     46 typedef uint32_t PromiseId;
     47 
     48 // This class is used on the main thread only.
     49 // Note: its addref/release is not (and can't be) thread safe!
     50 class MediaKeys final : public nsIObserver,
     51                        public nsWrapperCache,
     52                        public SupportsWeakPtr,
     53                        public DecoderDoctorLifeLogger<MediaKeys> {
     54  ~MediaKeys();
     55 
     56 public:
     57  NS_DECL_CYCLE_COLLECTING_ISUPPORTS
     58  NS_DECL_CYCLE_COLLECTION_WRAPPERCACHE_CLASS(MediaKeys)
     59 
     60  NS_DECL_NSIOBSERVER
     61 
     62  MediaKeys(nsPIDOMWindowInner* aParentWindow, const nsAString& aKeySystem,
     63            const MediaKeySystemConfiguration& aConfig);
     64 
     65  already_AddRefed<DetailedPromise> Init(ErrorResult& aRv);
     66 
     67  nsPIDOMWindowInner* GetParentObject() const;
     68 
     69  JSObject* WrapObject(JSContext* aCx,
     70                       JS::Handle<JSObject*> aGivenProto) override;
     71 
     72  nsresult Bind(HTMLMediaElement* aElement);
     73  void Unbind();
     74 
     75  // Checks if there's any activity happening that could capture the media
     76  // the keys are associated with and then expose that media outside of the
     77  // origin it is in.
     78  //
     79  // This method does not return the results of the check, but the MediaKeys
     80  // will notify mProxy of the results using `NotifyOutputProtectionStatus`.
     81  void CheckIsElementCapturePossible();
     82 
     83  // Javascript: readonly attribute DOMString keySystem;
     84  void GetKeySystem(nsString& retval) const;
     85 
     86  // JavaScript: MediaKeys.createSession()
     87  already_AddRefed<MediaKeySession> CreateSession(
     88      MediaKeySessionType aSessionType, ErrorResult& aRv);
     89 
     90  // JavaScript: MediaKeys.SetServerCertificate()
     91  already_AddRefed<DetailedPromise> SetServerCertificate(
     92      const ArrayBufferViewOrArrayBuffer& aServerCertificate, ErrorResult& aRv);
     93 
     94  already_AddRefed<MediaKeySession> GetSession(const nsAString& aSessionId);
     95 
     96  // Removes and returns MediaKeySession from the set of sessions awaiting
     97  // their sessionId to be assigned.
     98  already_AddRefed<MediaKeySession> GetPendingSession(uint32_t aToken);
     99 
    100  // Called once a Init() operation succeeds.
    101  void OnCDMCreated(PromiseId aId, const uint32_t aPluginId);
    102 
    103  // Called once the CDM generates a sessionId while servicing a
    104  // MediaKeySession.generateRequest() or MediaKeySession.load() call,
    105  // once the sessionId of a MediaKeySession is known.
    106  void OnSessionIdReady(MediaKeySession* aSession);
    107 
    108  // Called once a LoadSession succeeds.
    109  void OnSessionLoaded(PromiseId aId, bool aSuccess);
    110 
    111  // Called once a session has closed.
    112  void OnSessionClosed(MediaKeySession* aSession);
    113 
    114  CDMProxy* GetCDMProxy() { return mProxy; }
    115 
    116  // Makes a new promise, or nullptr on failure.
    117  already_AddRefed<DetailedPromise> MakePromise(ErrorResult& aRv,
    118                                                const nsACString& aName);
    119  // Stores promise in mPromises, returning an ID that can be used to retrieve
    120  // it later. The ID is passed to the CDM, so that it can signal specific
    121  // promises to be resolved.
    122  PromiseId StorePromise(DetailedPromise* aPromise);
    123 
    124  // Stores a map from promise id to pending session token. Using this
    125  // mapping, when a promise is rejected via its ID, we can check if the
    126  // promise corresponds to a pending session and retrieve that session
    127  // via the mapped-to token, and remove the pending session from the
    128  // list of sessions awaiting a session id.
    129  void ConnectPendingPromiseIdWithToken(PromiseId aId, uint32_t aToken);
    130 
    131  // Reject promise with the given exception.
    132  void RejectPromise(PromiseId aId, ErrorResult&& aException,
    133                     const nsCString& aReason);
    134  // Resolves promise with "undefined".
    135  void ResolvePromise(PromiseId aId);
    136 
    137  void Shutdown();
    138 
    139  // Called by CDMProxy when CDM crashes or shuts down. It is different from
    140  // Shutdown which is called from the script/dom side.
    141  void Terminated();
    142 
    143  // Returns true if this MediaKeys has been bound to a media element.
    144  bool IsBoundToMediaElement() const;
    145 
    146  // Indicates to a MediaKeys instance that the inner window parent of that
    147  // instance is being destroyed, this should prompt the keys to shutdown.
    148  void OnInnerWindowDestroy();
    149 
    150  void GetSessionsInfo(nsString& sessionsInfo);
    151 
    152  // JavaScript: MediaKeys.GetStatusForPolicy()
    153  already_AddRefed<Promise> GetStatusForPolicy(const MediaKeysPolicy& aPolicy,
    154                                               ErrorResult& aR);
    155  // Called by CDMProxy when CDM successfully GetStatusForPolicy.
    156  void ResolvePromiseWithKeyStatus(PromiseId aId,
    157                                   dom::MediaKeyStatus aMediaKeyStatus);
    158 
    159  template <typename T>
    160  void ResolvePromiseWithResult(PromiseId aId, const T& aResult) {
    161    RefPtr<DetailedPromise> promise(RetrievePromise(aId));
    162    if (!promise) {
    163      return;
    164    }
    165    promise->MaybeResolve(aResult);
    166  }
    167 
    168  // The topic used for requests related to mediakeys -- observe this to be
    169  // notified of such requests.
    170  constexpr static const char* kMediaKeysRequestTopic = "mediakeys-request";
    171 
    172  nsCString GetMediaKeySystemConfigurationString() const;
    173 
    174 private:
    175  // Instantiate CDMProxy instance.
    176  // It could be MediaDrmCDMProxy (Widevine on Fennec) or ChromiumCDMProxy (the
    177  // rest).
    178  already_AddRefed<CDMProxy> CreateCDMProxy();
    179 
    180  // Removes promise from mPromises, and returns it.
    181  already_AddRefed<DetailedPromise> RetrievePromise(PromiseId aId);
    182 
    183  // Helpers to connect and disconnect to the parent inner window. An inner
    184  // window should track (via weak ptr) MediaKeys created within it so we can
    185  // ensure MediaKeys are shutdown if that window is destroyed.
    186  void ConnectInnerWindow();
    187  void DisconnectInnerWindow();
    188 
    189  // Owning ref to proxy. The proxy has a weak reference back to the MediaKeys,
    190  // and the MediaKeys destructor clears the proxy's reference to the MediaKeys.
    191  RefPtr<CDMProxy> mProxy;
    192 
    193  // The HTMLMediaElement the MediaKeys are associated with. Note that a
    194  // MediaKeys instance may not be associated with any HTMLMediaElement so
    195  // this can be null (we also cannot rely on a media element to drive shutdown
    196  // for this reason).
    197  RefPtr<HTMLMediaElement> mElement;
    198 
    199  // The  inner window associated with an instance of MediaKeys. We will
    200  // shutdown the media keys when this Window is destroyed. We do this from the
    201  // window rather than a document to address the case where media keys can be
    202  // created in an about:blank document that then performs an async load -- this
    203  // recreates the document, but the inner window is preserved in such a case.
    204  // See https://bugzilla.mozilla.org/show_bug.cgi?id=1675360 for more info.
    205  nsCOMPtr<nsPIDOMWindowInner> mParent;
    206  const nsString mKeySystem;
    207  KeySessionHashMap mKeySessions;
    208  PromiseHashMap mPromises;
    209  PendingKeySessionsHashMap mPendingSessions;
    210  PromiseId mCreatePromiseId;
    211 
    212  // The principal of the relevant settings object.
    213  RefPtr<nsIPrincipal> mPrincipal;
    214  // The principal of the top level page. This can differ from mPrincipal if
    215  // we're in an iframe.
    216  RefPtr<nsIPrincipal> mTopLevelPrincipal;
    217 
    218  const MediaKeySystemConfiguration mConfig;
    219 
    220  PendingPromiseIdTokenHashMap mPromiseIdToken;
    221 
    222  // The topic a MediaKeys instance will observe to receive updates from
    223  // EncryptedMediaChild.
    224  constexpr static const char* kMediaKeysResponseTopic = "mediakeys-response";
    225  // Tracks if we've added an observer for responses from the associated
    226  // EncryptedMediaChild. When true an observer is already in place, otherwise
    227  // the observer has not yet been added.
    228  bool mObserverAdded = false;
    229  // Stores the json request we will send to EncryptedMediaChild when querying
    230  // output protection. Lazily populated upon first use.
    231  nsString mCaptureCheckRequestJson;
    232 };
    233 
    234 }  // namespace dom
    235 }  // namespace mozilla
    236 
    237 #endif  // mozilla_dom_mediakeys_h__