dom/security/featurepolicy/FeaturePolicyUtils.cpp
author Andrea Marchesini <amarchesini@mozilla.com>
Wed, 03 Oct 2018 12:39:44 +0200
changeset 439356 a1855d696e1ca886a4ed8f3668bc6830a8d1ccd6
parent 439141 2a4364e194c593caf63aa1aadc221d9f7ee551af
child 439378 56ffd7466acc844c078e39a23d3bdc4a7e05394c
permissions -rw-r--r--
Bug 1495358 - FeaturePolicy: vr, r=kip

/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

#include "FeaturePolicyUtils.h"
#include "mozilla/dom/FeaturePolicy.h"
#include "mozilla/StaticPrefs.h"
#include "nsIDocument.h"

using namespace mozilla::dom;

struct FeatureMap {
  const char* mFeatureName;

  enum {
    eAll,
    eSelf,
  } mDefaultAllowList;
};

/*
 * IMPORTANT: Do not change this list without review from a DOM peer _AND_ a
 * DOM Security peer!
 */
static FeatureMap sSupportedFeatures[] = {
  // TODO: not supported yet!!!
  { "autoplay", FeatureMap::eSelf },
  // TODO: not supported yet!!!
  { "camera", FeatureMap::eSelf  },
  { "encrypted-media", FeatureMap::eSelf  },
  // TODO: not supported yet!!!
  { "fullscreen", FeatureMap::eSelf  },
  // TODO: not supported yet!!!
  { "geolocation", FeatureMap::eSelf  },
  // TODO: not supported yet!!!
  { "microphone", FeatureMap::eSelf  },
  { "midi", FeatureMap::eSelf  },
  { "payment", FeatureMap::eSelf  },
  // TODO: not supported yet!!!
  { "speaker", FeatureMap::eSelf  },
  { "vr", FeatureMap::eSelf  },
};

/* static */ bool
FeaturePolicyUtils::IsSupportedFeature(const nsAString& aFeatureName)
{
  uint32_t numFeatures = (sizeof(sSupportedFeatures) / sizeof(sSupportedFeatures[0]));
  for (uint32_t i = 0; i < numFeatures; ++i) {
    if (aFeatureName.LowerCaseEqualsASCII(sSupportedFeatures[i].mFeatureName)) {
      return true;
    }
  }
  return false;
}

/* static */ void
FeaturePolicyUtils::ForEachFeature(const std::function<void(const char*)>& aCallback)
{
  uint32_t numFeatures = (sizeof(sSupportedFeatures) / sizeof(sSupportedFeatures[0]));
  for (uint32_t i = 0; i < numFeatures; ++i) {
    aCallback(sSupportedFeatures[i].mFeatureName);
  }
}

/* static */ void
FeaturePolicyUtils::DefaultAllowListFeature(const nsAString& aFeatureName,
                                            const nsAString& aDefaultOrigin,
                                            nsAString& aDefaultAllowList)
{
  uint32_t numFeatures = (sizeof(sSupportedFeatures) / sizeof(sSupportedFeatures[0]));
  for (uint32_t i = 0; i < numFeatures; ++i) {
    if (aFeatureName.LowerCaseEqualsASCII(sSupportedFeatures[i].mFeatureName)) {
      switch (sSupportedFeatures[i].mDefaultAllowList) {
        case FeatureMap::eAll:
          aDefaultAllowList.AppendASCII("*");
          return;

        case FeatureMap::eSelf:
          aDefaultAllowList = aDefaultOrigin;
          return;

        default:
          MOZ_CRASH("Unknown default value");
      }
    }
  }
}

/* static */ bool
FeaturePolicyUtils::AllowDefaultFeature(const nsAString& aFeatureName,
                                        const nsAString& aDefaultOrigin,
                                        const nsAString& aOrigin)
{
  uint32_t numFeatures = (sizeof(sSupportedFeatures) / sizeof(sSupportedFeatures[0]));
  for (uint32_t i = 0; i < numFeatures; ++i) {
    if (aFeatureName.LowerCaseEqualsASCII(sSupportedFeatures[i].mFeatureName)) {
      switch (sSupportedFeatures[i].mDefaultAllowList) {
        case FeatureMap::eAll:
          return true;
        case FeatureMap::eSelf:
          return aDefaultOrigin == aOrigin;
        default:
          MOZ_CRASH("Unknown default value");
      }
      return true;
    }
  }

  return false;
}

/* static */ bool
FeaturePolicyUtils::IsFeatureAllowed(nsIDocument* aDocument,
                                     const nsAString& aFeatureName)
{
  MOZ_ASSERT(aDocument);

  if (!StaticPrefs::dom_security_featurePolicy_enabled()) {
    return true;
  }

  if (!aDocument->IsHTMLDocument()) {
    return true;
  }

  FeaturePolicy* policy = aDocument->Policy();
  MOZ_ASSERT(policy);

  return policy->AllowsFeatureInternal(aFeatureName, policy->DefaultOrigin());
}