tor-browser

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

KeySystemConfig.h (10157B)


      1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
      2 /* vim:set ts=2 sw=2 sts=2 et cindent: */
      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
      5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      6 
      7 #ifndef DOM_MEDIA_EME_KEYSYSTEMCONFIG_H_
      8 #define DOM_MEDIA_EME_KEYSYSTEMCONFIG_H_
      9 
     10 #include "MediaData.h"
     11 #include "mozilla/MozPromise.h"
     12 #include "mozilla/dom/MediaKeySystemAccessBinding.h"
     13 #include "mozilla/dom/MediaKeysBinding.h"
     14 #include "nsString.h"
     15 #include "nsTArray.h"
     16 
     17 namespace mozilla {
     18 
     19 struct KeySystemConfigRequest;
     20 
     21 struct KeySystemConfig {
     22 public:
     23  using SupportedConfigsPromise =
     24      MozPromise<nsTArray<KeySystemConfig>, bool /* aIgnored */,
     25                 /* IsExclusive = */ true>;
     26  using KeySystemConfigPromise =
     27      MozPromise<dom::MediaKeySystemConfiguration, bool /* aIgnored */,
     28                 /* IsExclusive = */ true>;
     29 
     30  // EME MediaKeysRequirement:
     31  // https://www.w3.org/TR/encrypted-media/#dom-mediakeysrequirement
     32  MOZ_DEFINE_ENUM_CLASS_WITH_TOSTRING_AT_CLASS_SCOPE(Requirement,
     33                                                     (Required, Optional,
     34                                                      NotAllowed));
     35 
     36  // EME MediaKeySessionType:
     37  // https://www.w3.org/TR/encrypted-media/#dom-mediakeysessiontype
     38  MOZ_DEFINE_ENUM_CLASS_WITH_TOSTRING_AT_CLASS_SCOPE(SessionType,
     39                                                     (Temporary,
     40                                                      PersistentLicense));
     41 
     42  using EMECodecString = nsCString;
     43  static constexpr auto EME_CODEC_AAC = "aac"_ns;
     44  static constexpr auto EME_CODEC_OPUS = "opus"_ns;
     45  static constexpr auto EME_CODEC_VORBIS = "vorbis"_ns;
     46  static constexpr auto EME_CODEC_FLAC = "flac"_ns;
     47  static constexpr auto EME_CODEC_H264 = "h264"_ns;
     48  static constexpr auto EME_CODEC_AV1 = "av1"_ns;
     49  static constexpr auto EME_CODEC_VP8 = "vp8"_ns;
     50  static constexpr auto EME_CODEC_VP9 = "vp9"_ns;
     51  static constexpr auto EME_CODEC_HEVC = "hevc"_ns;
     52 
     53  using EMEEncryptionSchemeString = nsCString;
     54  static constexpr auto EME_ENCRYPTION_SCHEME_CENC = "cenc"_ns;
     55  static constexpr auto EME_ENCRYPTION_SCHEME_CBCS = "cbcs"_ns;
     56 
     57  // A codec can be decrypted-and-decoded by the CDM, or only decrypted
     58  // by the CDM and decoded by Gecko. Not both.
     59  struct ContainerSupport {
     60    ContainerSupport() = default;
     61    ~ContainerSupport() = default;
     62    ContainerSupport(const ContainerSupport& aOther) {
     63      mCodecsDecoded = aOther.mCodecsDecoded.Clone();
     64      mCodecsDecrypted = aOther.mCodecsDecrypted.Clone();
     65    }
     66    ContainerSupport& operator=(const ContainerSupport& aOther) {
     67      if (this == &aOther) {
     68        return *this;
     69      }
     70      mCodecsDecoded = aOther.mCodecsDecoded.Clone();
     71      mCodecsDecrypted = aOther.mCodecsDecrypted.Clone();
     72      return *this;
     73    }
     74    ContainerSupport(ContainerSupport&& aOther) = default;
     75    ContainerSupport& operator=(ContainerSupport&&) = default;
     76 
     77    bool IsSupported() const {
     78      return !mCodecsDecoded.IsEmpty() || !mCodecsDecrypted.IsEmpty();
     79    }
     80 
     81    // True if a codec and scheme pair can be decrypted and decoded
     82    bool DecryptsAndDecodes(
     83        const EMECodecString& aCodec,
     84        const Maybe<CryptoScheme>& aScheme = Nothing()) const {
     85      return CheckCodecAndSchemePair(mCodecsDecoded, aCodec, aScheme);
     86    }
     87 
     88    // True if a codec and scheme pair can be decrypted
     89    bool Decrypts(const EMECodecString& aCodec,
     90                  const Maybe<CryptoScheme>& aScheme = Nothing()) const {
     91      return CheckCodecAndSchemePair(mCodecsDecrypted, aCodec, aScheme);
     92    }
     93 
     94    void SetCanDecryptAndDecode(
     95        const EMECodecString& aCodec,
     96        const Maybe<CryptoSchemeSet>& aSchemes = Nothing{}) {
     97      // Can't both decrypt and decrypt-and-decode a codec.
     98      MOZ_ASSERT(!ContainsDecryptedOnlyCodec(aCodec));
     99      // Prevent duplicates.
    100      MOZ_ASSERT(!ContainsDecryptedAndDecodedCodec(aCodec));
    101 
    102      mCodecsDecoded.AppendElement(CodecSchemePair{aCodec, aSchemes});
    103    }
    104 
    105    void SetCanDecrypt(const EMECodecString& aCodec,
    106                       const Maybe<CryptoSchemeSet>& aSchemes = Nothing{}) {
    107      // Prevent duplicates.
    108      MOZ_ASSERT(!ContainsDecryptedOnlyCodec(aCodec));
    109      // Can't both decrypt and decrypt-and-decode a codec.
    110      MOZ_ASSERT(!ContainsDecryptedAndDecodedCodec(aCodec));
    111      mCodecsDecrypted.AppendElement(CodecSchemePair{aCodec, aSchemes});
    112    }
    113 
    114    EMECodecString GetDebugInfo() const {
    115      EMECodecString info;
    116      info.AppendLiteral("decoding-and-decrypting:[");
    117      for (size_t idx = 0; idx < mCodecsDecoded.Length(); idx++) {
    118        const auto& cur = mCodecsDecoded[idx];
    119        info.Append(cur.first);
    120        if (cur.second) {
    121          info.AppendLiteral("(");
    122          info.Append(CryptoSchemeSetToString(*cur.second));
    123          info.AppendLiteral(")");
    124        } else {
    125          info.AppendLiteral("(all)");
    126        }
    127        if (idx + 1 < mCodecsDecoded.Length()) {
    128          info.AppendLiteral(",");
    129        }
    130      }
    131      info.AppendLiteral("],");
    132      info.AppendLiteral("decrypting-only:[");
    133      for (size_t idx = 0; idx < mCodecsDecrypted.Length(); idx++) {
    134        const auto& cur = mCodecsDecrypted[idx];
    135        info.Append(cur.first);
    136        if (cur.second) {
    137          info.AppendLiteral("(");
    138          info.Append(CryptoSchemeSetToString(*cur.second));
    139          info.AppendLiteral(")");
    140        } else {
    141          info.AppendLiteral("(all)");
    142        }
    143        if (idx + 1 < mCodecsDecrypted.Length()) {
    144          info.AppendLiteral(",");
    145        }
    146      }
    147      info.AppendLiteral("]");
    148      return info;
    149    }
    150 
    151   private:
    152    using CodecSchemePair = std::pair<EMECodecString, Maybe<CryptoSchemeSet>>;
    153    // These two arrays are exclusive, the codec in one array can't appear on
    154    // another array. If CryptoSchemeSet is nothing, that means the codec has
    155    // support for all schemes, which is our default. Setting CryptoSchemeSet
    156    // explicitly can restrict avaiable schemes for a codec.
    157    nsTArray<CodecSchemePair> mCodecsDecoded;
    158    nsTArray<CodecSchemePair> mCodecsDecrypted;
    159 
    160    bool ContainsDecryptedOnlyCodec(const EMECodecString& aCodec) const {
    161      return std::any_of(
    162          mCodecsDecrypted.begin(), mCodecsDecrypted.end(),
    163          [&](const auto& aPair) { return aPair.first.Equals(aCodec); });
    164    }
    165    bool ContainsDecryptedAndDecodedCodec(const EMECodecString& aCodec) const {
    166      return std::any_of(
    167          mCodecsDecoded.begin(), mCodecsDecoded.end(),
    168          [&](const auto& aPair) { return aPair.first.Equals(aCodec); });
    169    }
    170    bool CheckCodecAndSchemePair(const nsTArray<CodecSchemePair>& aArray,
    171                                 const EMECodecString& aCodec,
    172                                 const Maybe<CryptoScheme>& aScheme) const {
    173      return std::any_of(aArray.begin(), aArray.end(), [&](const auto& aPair) {
    174        if (!aPair.first.Equals(aCodec)) {
    175          return false;
    176        }
    177        // No scheme is specified, which means accepting all schemes.
    178        if (!aPair.second || !aScheme) {
    179          return true;
    180        }
    181        return aPair.second->contains(*aScheme);
    182      });
    183    }
    184  };
    185 
    186  // Return true if given key system is supported on the current device.
    187  static bool Supports(const nsAString& aKeySystem);
    188 
    189  enum class DecryptionInfo : uint8_t {
    190    Software,
    191    Hardware,
    192  };
    193  static RefPtr<SupportedConfigsPromise> CreateKeySystemConfigs(
    194      const nsTArray<KeySystemConfigRequest>& aRequests);
    195  static void GetGMPKeySystemConfigs(dom::Promise* aPromise);
    196 
    197  KeySystemConfig() = default;
    198  ~KeySystemConfig() = default;
    199  explicit KeySystemConfig(const KeySystemConfig& aOther) {
    200    mKeySystem = aOther.mKeySystem;
    201    mInitDataTypes = aOther.mInitDataTypes.Clone();
    202    mPersistentState = aOther.mPersistentState;
    203    mDistinctiveIdentifier = aOther.mDistinctiveIdentifier;
    204    mSessionTypes = aOther.mSessionTypes.Clone();
    205    mVideoRobustness = aOther.mVideoRobustness.Clone();
    206    mAudioRobustness = aOther.mAudioRobustness.Clone();
    207    mMP4 = aOther.mMP4;
    208    mWebM = aOther.mWebM;
    209  }
    210  KeySystemConfig& operator=(const KeySystemConfig& aOther) {
    211    if (this == &aOther) {
    212      return *this;
    213    }
    214    mKeySystem = aOther.mKeySystem;
    215    mInitDataTypes = aOther.mInitDataTypes.Clone();
    216    mPersistentState = aOther.mPersistentState;
    217    mDistinctiveIdentifier = aOther.mDistinctiveIdentifier;
    218    mSessionTypes = aOther.mSessionTypes.Clone();
    219    mVideoRobustness = aOther.mVideoRobustness.Clone();
    220    mAudioRobustness = aOther.mAudioRobustness.Clone();
    221    mMP4 = aOther.mMP4;
    222    mWebM = aOther.mWebM;
    223    return *this;
    224  }
    225  KeySystemConfig(KeySystemConfig&&) = default;
    226  KeySystemConfig& operator=(KeySystemConfig&&) = default;
    227 
    228  nsString GetDebugInfo() const;
    229 
    230  nsString mKeySystem;
    231  nsTArray<nsString> mInitDataTypes;
    232  Requirement mPersistentState = Requirement::NotAllowed;
    233  Requirement mDistinctiveIdentifier = Requirement::NotAllowed;
    234  nsTArray<SessionType> mSessionTypes;
    235  nsTArray<nsString> mVideoRobustness;
    236  nsTArray<nsString> mAudioRobustness;
    237  ContainerSupport mMP4;
    238  ContainerSupport mWebM;
    239 
    240 private:
    241  static void CreateClearKeyKeySystemConfigs(
    242      const KeySystemConfigRequest& aRequest,
    243      nsTArray<KeySystemConfig>& aOutConfigs);
    244  static void CreateWivineL3KeySystemConfigs(
    245      const KeySystemConfigRequest& aRequest,
    246      nsTArray<KeySystemConfig>& aOutConfigs);
    247 };
    248 
    249 struct KeySystemConfigRequest final {
    250  KeySystemConfigRequest(const nsAString& aKeySystem,
    251                         KeySystemConfig::DecryptionInfo aDecryption,
    252                         bool aIsPrivateBrowsing)
    253      : mKeySystem(aKeySystem),
    254        mDecryption(aDecryption),
    255        mIsPrivateBrowsing(aIsPrivateBrowsing) {}
    256  const nsString mKeySystem;
    257  const KeySystemConfig::DecryptionInfo mDecryption;
    258  const bool mIsPrivateBrowsing;
    259 };
    260 
    261 KeySystemConfig::SessionType ConvertToKeySystemConfigSessionType(
    262    dom::MediaKeySessionType aType);
    263 
    264 }  // namespace mozilla
    265 
    266 #endif  // DOM_MEDIA_EME_KEYSYSTEMCONFIG_H_