Bug 906420 - Part 3: Either expose files or strings generated by system drag or clipboard events to content, not both, r=baku

This commit is contained in:
Michael Layzell 2016-05-31 15:03:44 -04:00
parent 038736ebef
commit e3f9006f22
6 changed files with 123 additions and 69 deletions

View File

@ -323,6 +323,10 @@ DataTransfer::GetTypes(ErrorResult& aRv) const
DataTransferItem* item = items->ElementAt(i);
MOZ_ASSERT(item);
if (item->ChromeOnly() && !nsContentUtils::LegacyIsCallerChromeOrNativeCode()) {
continue;
}
nsAutoString type;
item->GetType(type);
if (NS_WARN_IF(!types->Add(type))) {
@ -538,13 +542,26 @@ DataTransfer::MozTypesAt(uint32_t aIndex, ErrorResult& aRv) const
// note that you can retrieve the types regardless of their principal
const nsTArray<RefPtr<DataTransferItem>>& items = *mItems->MozItemsAt(aIndex);
bool addFile = false;
for (uint32_t i = 0; i < items.Length(); i++) {
if (items[i]->ChromeOnly() && !nsContentUtils::LegacyIsCallerChromeOrNativeCode()) {
continue;
}
nsAutoString type;
items[i]->GetType(type);
if (NS_WARN_IF(!types->Add(type))) {
aRv.Throw(NS_ERROR_FAILURE);
return nullptr;
}
if (items[i]->Kind() == DataTransferItem::KIND_FILE) {
addFile = true;
}
}
if (addFile) {
types->Add(NS_LITERAL_STRING("Files"));
}
}
@ -594,16 +611,6 @@ DataTransfer::GetDataAtInternal(const nsAString& aFormat, uint32_t aIndex,
nsAutoString format;
GetRealFormat(aFormat, format);
const nsTArray<RefPtr<DataTransferItem>>& items = *mItems->MozItemsAt(aIndex);
if (!aFormat.EqualsLiteral(kFileMime) &&
!nsContentUtils::IsSystemPrincipal(aSubjectPrincipal)) {
for (uint32_t i = 0; i < items.Length(); ++i) {
if (items[i]->IsFile()) {
return NS_OK;
}
}
}
// Check if the caller is allowed to access the drag data. Callers with
// chrome privileges can always read the data. During the
// drop event, allow retrieving the data except in the case where the
@ -622,6 +629,11 @@ DataTransfer::GetDataAtInternal(const nsAString& aFormat, uint32_t aIndex,
return NS_OK;
}
// If we have chrome only content, and we aren't chrome, don't allow access
if (!nsContentUtils::IsSystemPrincipal(aSubjectPrincipal) && item->ChromeOnly()) {
return NS_OK;
}
if (item->Principal() && checkFormatItemPrincipal &&
!aSubjectPrincipal->Subsumes(item->Principal())) {
return NS_ERROR_DOM_SECURITY_ERR;
@ -1244,7 +1256,10 @@ DataTransfer::SetDataWithPrincipal(const nsAString& aFormat,
ErrorResult rv;
RefPtr<DataTransferItem> item =
mItems->SetDataWithPrincipal(format, aData, aIndex, aPrincipal, false, rv);
mItems->SetDataWithPrincipal(format, aData, aIndex, aPrincipal,
/* aInsertOnly = */ false,
/* aHidden= */ false,
rv);
return rv.StealNSResult();
}
@ -1282,24 +1297,39 @@ DataTransfer::GetRealFormat(const nsAString& aInFormat,
aOutFormat.Assign(lowercaseFormat);
}
void
nsresult
DataTransfer::CacheExternalData(const char* aFormat, uint32_t aIndex,
nsIPrincipal* aPrincipal)
nsIPrincipal* aPrincipal, bool aHidden)
{
ErrorResult rv;
RefPtr<DataTransferItem> item;
if (strcmp(aFormat, kUnicodeMime) == 0) {
SetDataWithPrincipal(NS_LITERAL_STRING("text/plain"), nullptr, aIndex,
aPrincipal);
return;
item = mItems->SetDataWithPrincipal(NS_LITERAL_STRING("text/plain"), nullptr,
aIndex, aPrincipal, false, aHidden, rv);
if (NS_WARN_IF(rv.Failed())) {
return rv.StealNSResult();
}
return NS_OK;
}
if (strcmp(aFormat, kURLDataMime) == 0) {
SetDataWithPrincipal(NS_LITERAL_STRING("text/uri-list"), nullptr, aIndex,
aPrincipal);
return;
item = mItems->SetDataWithPrincipal(NS_LITERAL_STRING("text/uri-list"), nullptr,
aIndex, aPrincipal, false, aHidden, rv);
if (NS_WARN_IF(rv.Failed())) {
return rv.StealNSResult();
}
return NS_OK;
}
SetDataWithPrincipal(NS_ConvertUTF8toUTF16(aFormat), nullptr, aIndex,
aPrincipal);
nsAutoString format;
GetRealFormat(NS_ConvertUTF8toUTF16(aFormat), format);
item = mItems->SetDataWithPrincipal(format, nullptr, aIndex,
aPrincipal, false, aHidden, rv);
if (NS_WARN_IF(rv.Failed())) {
return rv.StealNSResult();
}
return NS_OK;
}
// there isn't a way to get a list of the formats that might be available on
@ -1337,6 +1367,9 @@ DataTransfer::CacheExternalDragFormats()
uint32_t count;
dragSession->GetNumDropItems(&count);
for (uint32_t c = 0; c < count; c++) {
bool hasFileData = false;
dragSession->IsDataFlavorSupported(kFileMime, &hasFileData);
// First, check for the special format that holds custom types.
bool supported;
dragSession->IsDataFlavorSupported(kCustomTypesMime, &supported);
@ -1354,7 +1387,7 @@ DataTransfer::CacheExternalDragFormats()
// if the format is supported, add an item to the array with null as
// the data. When retrieved, GetRealData will read the data.
if (supported) {
CacheExternalData(kFormats[f], c, sysPrincipal);
CacheExternalData(kFormats[f], c, sysPrincipal, /* hidden = */ f && hasFileData);
}
}
}
@ -1380,6 +1413,11 @@ DataTransfer::CacheExternalClipboardFormats()
nsCOMPtr<nsIPrincipal> sysPrincipal;
ssm->GetSystemPrincipal(getter_AddRefs(sysPrincipal));
// Check if the clipboard has any files
bool hasFileData = false;
const char *fileMime[] = { kFileMime };
clipboard->HasDataMatchingFlavors(fileMime, 1, mClipboardType, &hasFileData);
// there isn't a way to get a list of the formats that might be available on
// all platforms, so just check for the types that can actually be imported.
// Note that the loop below assumes that kCustomTypesMime will be first.
@ -1398,7 +1436,8 @@ DataTransfer::CacheExternalClipboardFormats()
if (f == 0) {
FillInExternalCustomTypes(0, sysPrincipal);
} else {
CacheExternalData(formats[f], 0, sysPrincipal);
// If we aren't the file data, and we have file data, we want to be hidden
CacheExternalData(formats[f], 0, sysPrincipal, /* hidden = */ f != 1 && hasFileData);
}
}
}

View File

@ -258,8 +258,8 @@ protected:
// caches text and uri-list data formats that exist in the drag service or
// clipboard for retrieval later.
void CacheExternalData(const char* aFormat, uint32_t aIndex,
nsIPrincipal* aPrincipal);
nsresult CacheExternalData(const char* aFormat, uint32_t aIndex,
nsIPrincipal* aPrincipal, bool aHidden);
// caches the formats that exist in the drag service that were added by an
// external drag

View File

@ -31,22 +31,6 @@ FileMimeNameData kFileMimeNameMap[] = {
{ kPNGImageMime, "GenericImageNamePNG" },
};
already_AddRefed<mozilla::dom::File>
FileFromISupports(nsISupports* aSupports)
{
MOZ_ASSERT(aSupports);
nsCOMPtr<nsIDOMBlob> domBlob = do_QueryInterface(aSupports);
if (domBlob) {
// Get out the blob - this is OK, because nsIDOMBlob is a builtinclass
// and the only implementer is Blob.
mozilla::dom::Blob* blob = static_cast<mozilla::dom::Blob*>(domBlob.get());
return blob->ToFile();
}
return nullptr;
}
} // anonymous namespace
namespace mozilla {
@ -198,22 +182,6 @@ DataTransferItem::FillInExternalData()
// whatever type happens to actually be stored into a dom::File.
RefPtr<File> file = FileFromISupports(data);
if (!file) {
if (nsCOMPtr<nsIFile> ifile = do_QueryInterface(data)) {
file = File::CreateFromFile(GetParentObject(), ifile);
} else if (nsCOMPtr<nsIInputStream> stream = do_QueryInterface(data)) {
// This consumes the stream object
ErrorResult rv;
file = CreateFileFromInputStream(GetParentObject(), stream, rv);
if (NS_WARN_IF(rv.Failed())) {
rv.SuppressException();
}
} else if (nsCOMPtr<BlobImpl> blobImpl = do_QueryInterface(data)) {
MOZ_ASSERT(blobImpl->IsFile());
file = File::Create(GetParentObject(), blobImpl);
}
}
MOZ_ASSERT(file, "Invalid format for Kind() == KIND_FILE");
data = do_QueryObject(file);
@ -280,6 +248,37 @@ DataTransferItem::GetAsFile(ErrorResult& aRv)
return file.forget();
}
already_AddRefed<File>
DataTransferItem::FileFromISupports(nsISupports* aSupports)
{
MOZ_ASSERT(aSupports);
RefPtr<File> file;
nsCOMPtr<nsIDOMBlob> domBlob = do_QueryInterface(aSupports);
if (domBlob) {
// Get out the blob - this is OK, because nsIDOMBlob is a builtinclass
// and the only implementer is Blob.
Blob* blob = static_cast<Blob*>(domBlob.get());
file = blob->ToFile();
} else if (nsCOMPtr<nsIFile> ifile = do_QueryInterface(aSupports)) {
printf("Creating a File from a nsIFile!\n");
file = File::CreateFromFile(GetParentObject(), ifile);
} else if (nsCOMPtr<nsIInputStream> stream = do_QueryInterface(aSupports)) {
// This consumes the stream object
ErrorResult rv;
file = CreateFileFromInputStream(GetParentObject(), stream, rv);
if (NS_WARN_IF(rv.Failed())) {
rv.SuppressException();
}
} else if (nsCOMPtr<BlobImpl> blobImpl = do_QueryInterface(aSupports)) {
MOZ_ASSERT(blobImpl->IsFile());
file = File::Create(GetParentObject(), blobImpl);
}
return file.forget();
}
already_AddRefed<File>
DataTransferItem::CreateFileFromInputStream(nsISupports* aParent,
nsIInputStream* aStream,
@ -321,7 +320,7 @@ DataTransferItem::CreateFileFromInputStream(nsISupports* aParent,
}
void
DataTransferItem::GetAsString(const RefPtr<FunctionStringCallback>& aCallback,
DataTransferItem::GetAsString(FunctionStringCallback* aCallback,
ErrorResult& aRv)
{
if (!aCallback || mKind != KIND_STRING) {
@ -340,7 +339,7 @@ DataTransferItem::GetAsString(const RefPtr<FunctionStringCallback>& aCallback,
class GASRunnable final : public Runnable
{
public:
GASRunnable(const RefPtr<FunctionStringCallback>& aCallback,
GASRunnable(FunctionStringCallback* aCallback,
const nsAString& aStringData)
: mCallback(aCallback), mStringData(aStringData)
{}

View File

@ -35,14 +35,13 @@ public:
};
DataTransferItem(DataTransferItemList* aParent, const nsAString& aType)
: mIndex(0), mKind(KIND_OTHER), mType(aType), mParent(aParent)
: mIndex(0), mChromeOnly(false), mKind(KIND_OTHER), mType(aType), mParent(aParent)
{}
already_AddRefed<DataTransferItem> Clone(DataTransferItemList* aParent) const;
virtual JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
void GetAsString(const RefPtr<FunctionStringCallback>& aCallback,
ErrorResult& aRv);
void GetAsString(FunctionStringCallback* aCallback, ErrorResult& aRv);
void GetKind(nsAString& aKind) const
{
switch (mKind) {
@ -108,8 +107,18 @@ public:
}
void FillInExternalData();
bool ChromeOnly() const
{
return mChromeOnly;
}
void SetChromeOnly(bool aChromeOnly)
{
mChromeOnly = aChromeOnly;
}
private:
~DataTransferItem() {}
already_AddRefed<File> FileFromISupports(nsISupports* aParent);
already_AddRefed<File> CreateFileFromInputStream(nsISupports* aParent,
nsIInputStream* aStream,
ErrorResult& aRv);
@ -117,6 +126,7 @@ private:
// The index in the 2d mIndexedItems array
uint32_t mIndex;
bool mChromeOnly;
eKind mKind;
nsString mType;
nsCOMPtr<nsIVariant> mData;

View File

@ -212,7 +212,9 @@ DataTransferItemList::Add(const nsAString& aData,
RefPtr<DataTransferItem> item =
SetDataWithPrincipal(format, data, 0,
nsContentUtils::SubjectPrincipal(),
true, aRv);
/* aInsertOnly = */ true,
/* aHidden = */ false,
aRv);
if (NS_WARN_IF(aRv.Failed())) {
return nullptr;
}
@ -243,7 +245,7 @@ DataTransferItemList::Add(File& aData, ErrorResult& aRv)
RefPtr<DataTransferItem> item =
SetDataWithPrincipal(type, data, index,
nsContentUtils::SubjectPrincipal(),
true, aRv);
true, false, aRv);
if (NS_WARN_IF(aRv.Failed())) {
return nullptr;
}
@ -332,6 +334,7 @@ DataTransferItemList::SetDataWithPrincipal(const nsAString& aType,
uint32_t aIndex,
nsIPrincipal* aPrincipal,
bool aInsertOnly,
bool aHidden,
ErrorResult& aRv)
{
if (aIndex < mIndexedItems.Length()) {
@ -391,7 +394,7 @@ DataTransferItemList::SetDataWithPrincipal(const nsAString& aType,
}
// Add the new item
RefPtr<DataTransferItem> item = AppendNewItem(aIndex, aType, aData, aPrincipal);
RefPtr<DataTransferItem> item = AppendNewItem(aIndex, aType, aData, aPrincipal, aHidden);
if (item->Kind() == DataTransferItem::KIND_FILE) {
RegenerateFiles();
@ -404,7 +407,8 @@ DataTransferItem*
DataTransferItemList::AppendNewItem(uint32_t aIndex,
const nsAString& aType,
nsIVariant* aData,
nsIPrincipal* aPrincipal)
nsIPrincipal* aPrincipal,
bool aHidden)
{
if (mIndexedItems.Length() <= aIndex) {
MOZ_ASSERT(mIndexedItems.Length() == aIndex);
@ -414,6 +418,7 @@ DataTransferItemList::AppendNewItem(uint32_t aIndex,
item->SetIndex(aIndex);
item->SetPrincipal(aPrincipal);
item->SetData(aData);
item->SetChromeOnly(aHidden);
mIndexedItems[aIndex].AppendElement(item);
@ -422,7 +427,7 @@ DataTransferItemList::AppendNewItem(uint32_t aIndex,
// which is not a file to a non-zero index, invariants could be broken.
// (namely the invariant that there are not 2 non-file entries in the items
// array with the same type)
if (item->Kind() == DataTransferItem::KIND_FILE || aIndex == 0) {
if (!aHidden && (item->Kind() == DataTransferItem::KIND_FILE || aIndex == 0)) {
mItems.AppendElement(item);
}

View File

@ -75,7 +75,7 @@ public:
already_AddRefed<DataTransferItem>
SetDataWithPrincipal(const nsAString& aType, nsIVariant* aData,
uint32_t aIndex, nsIPrincipal* aPrincipal,
bool aInsertOnly, ErrorResult& aRv);
bool aInsertOnly, bool aHidden, ErrorResult& aRv);
FileList* Files();
@ -97,7 +97,8 @@ private:
void ClearDataHelper(DataTransferItem* aItem, uint32_t aIndexHint,
uint32_t aMozOffsetHint, ErrorResult& aRv);
DataTransferItem* AppendNewItem(uint32_t aIndex, const nsAString& aType,
nsIVariant* aData, nsIPrincipal* aPrincipal);
nsIVariant* aData, nsIPrincipal* aPrincipal,
bool aHidden);
void RegenerateFiles();
~DataTransferItemList() {}