mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-30 00:01:50 +00:00
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:
parent
038736ebef
commit
e3f9006f22
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
{}
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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() {}
|
||||
|
Loading…
Reference in New Issue
Block a user