diff --git a/dom/events/DataTransfer.cpp b/dom/events/DataTransfer.cpp index bc0dfa6f7f55..cb4c6a23ab3a 100644 --- a/dom/events/DataTransfer.cpp +++ b/dom/events/DataTransfer.cpp @@ -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>& 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>& 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 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 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 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); } } } diff --git a/dom/events/DataTransfer.h b/dom/events/DataTransfer.h index 12103e20b584..d0f4bfb8b04c 100644 --- a/dom/events/DataTransfer.h +++ b/dom/events/DataTransfer.h @@ -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 diff --git a/dom/events/DataTransferItem.cpp b/dom/events/DataTransferItem.cpp index c4f15fb1b3f4..eb73a486e366 100644 --- a/dom/events/DataTransferItem.cpp +++ b/dom/events/DataTransferItem.cpp @@ -31,22 +31,6 @@ FileMimeNameData kFileMimeNameMap[] = { { kPNGImageMime, "GenericImageNamePNG" }, }; -already_AddRefed -FileFromISupports(nsISupports* aSupports) -{ - MOZ_ASSERT(aSupports); - - nsCOMPtr 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(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 = FileFromISupports(data); - if (!file) { - if (nsCOMPtr ifile = do_QueryInterface(data)) { - file = File::CreateFromFile(GetParentObject(), ifile); - } else if (nsCOMPtr 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 = 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 +DataTransferItem::FileFromISupports(nsISupports* aSupports) +{ + MOZ_ASSERT(aSupports); + + RefPtr file; + + nsCOMPtr 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(domBlob.get()); + file = blob->ToFile(); + } else if (nsCOMPtr ifile = do_QueryInterface(aSupports)) { + printf("Creating a File from a nsIFile!\n"); + file = File::CreateFromFile(GetParentObject(), ifile); + } else if (nsCOMPtr 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 = do_QueryInterface(aSupports)) { + MOZ_ASSERT(blobImpl->IsFile()); + file = File::Create(GetParentObject(), blobImpl); + } + + return file.forget(); +} + already_AddRefed DataTransferItem::CreateFileFromInputStream(nsISupports* aParent, nsIInputStream* aStream, @@ -321,7 +320,7 @@ DataTransferItem::CreateFileFromInputStream(nsISupports* aParent, } void -DataTransferItem::GetAsString(const RefPtr& aCallback, +DataTransferItem::GetAsString(FunctionStringCallback* aCallback, ErrorResult& aRv) { if (!aCallback || mKind != KIND_STRING) { @@ -340,7 +339,7 @@ DataTransferItem::GetAsString(const RefPtr& aCallback, class GASRunnable final : public Runnable { public: - GASRunnable(const RefPtr& aCallback, + GASRunnable(FunctionStringCallback* aCallback, const nsAString& aStringData) : mCallback(aCallback), mStringData(aStringData) {} diff --git a/dom/events/DataTransferItem.h b/dom/events/DataTransferItem.h index bc425bf098a5..4b8a1a1f1039 100644 --- a/dom/events/DataTransferItem.h +++ b/dom/events/DataTransferItem.h @@ -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 Clone(DataTransferItemList* aParent) const; virtual JSObject* WrapObject(JSContext* aCx, JS::Handle aGivenProto) override; - void GetAsString(const RefPtr& 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 FileFromISupports(nsISupports* aParent); already_AddRefed 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 mData; diff --git a/dom/events/DataTransferItemList.cpp b/dom/events/DataTransferItemList.cpp index 8673e4b09b5a..1434d5f813ec 100644 --- a/dom/events/DataTransferItemList.cpp +++ b/dom/events/DataTransferItemList.cpp @@ -212,7 +212,9 @@ DataTransferItemList::Add(const nsAString& aData, RefPtr 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 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 item = AppendNewItem(aIndex, aType, aData, aPrincipal); + RefPtr 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); } diff --git a/dom/events/DataTransferItemList.h b/dom/events/DataTransferItemList.h index 8c28cb1723d2..a179ef19af32 100644 --- a/dom/events/DataTransferItemList.h +++ b/dom/events/DataTransferItemList.h @@ -75,7 +75,7 @@ public: already_AddRefed 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() {}