nsresult DataTransfer::CacheExternalData(const char* aFormat, uint32_t aIndex, nsIPrincipal* aPrincipal, bool aHidden) { ErrorResult rv; RefPtr<DataTransferItem> item; if (strcmp(aFormat, kUnicodeMime) == 0) { 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) { 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; } 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; }
nsresult DataTransfer::SetDataWithPrincipal(const nsAString& aFormat, nsIVariant* aData, uint32_t aIndex, nsIPrincipal* aPrincipal) { nsAutoString format; GetRealFormat(aFormat, format); // check if the item for the format already exists. In that case, // just replace it. TransferItem* formatitem; if (aIndex < mItems.Length()) { nsTArray<TransferItem>& item = mItems[aIndex]; uint32_t count = item.Length(); for (uint32_t i = 0; i < count; i++) { TransferItem& itemformat = item[i]; if (itemformat.mFormat.Equals(format)) { // don't allow replacing data that has a stronger principal bool subsumes; if (itemformat.mPrincipal && aPrincipal && (NS_FAILED(aPrincipal->Subsumes(itemformat.mPrincipal, &subsumes)) || !subsumes)) { return NS_ERROR_DOM_SECURITY_ERR; } itemformat.mPrincipal = aPrincipal; itemformat.mData = aData; return NS_OK; } } // add a new format formatitem = item.AppendElement(); } else { NS_ASSERTION(aIndex == mItems.Length(), "Index out of range"); // add a new index nsTArray<TransferItem>* item = mItems.AppendElement(); NS_ENSURE_TRUE(item, NS_ERROR_OUT_OF_MEMORY); formatitem = item->AppendElement(); } NS_ENSURE_TRUE(formatitem, NS_ERROR_OUT_OF_MEMORY); formatitem->mFormat = format; formatitem->mPrincipal = aPrincipal; formatitem->mData = aData; return NS_OK; }
void DataTransfer::MozClearDataAtHelper(const nsAString& aFormat, uint32_t aIndex, ErrorResult& aRv) { MOZ_ASSERT(!mReadOnly); MOZ_ASSERT(aIndex < mItems.Length()); MOZ_ASSERT(aIndex == 0 || (mEventType != NS_CUT && mEventType != NS_COPY && mEventType != NS_PASTE)); nsAutoString format; GetRealFormat(aFormat, format); nsresult rv = NS_OK; nsIPrincipal* principal = GetCurrentPrincipal(&rv); if (NS_FAILED(rv)) { aRv = rv; return; } // if the format is empty, clear all formats bool clearall = format.IsEmpty(); nsTArray<TransferItem>& item = mItems[aIndex]; // count backwards so that the count and index don't have to be adjusted // after removing an element for (int32_t i = item.Length() - 1; i >= 0; i--) { TransferItem& formatitem = item[i]; if (clearall || formatitem.mFormat.Equals(format)) { // don't allow removing data that has a stronger principal bool subsumes; if (formatitem.mPrincipal && principal && (NS_FAILED(principal->Subsumes(formatitem.mPrincipal, &subsumes)) || !subsumes)) { aRv.Throw(NS_ERROR_DOM_SECURITY_ERR); return; } item.RemoveElementAt(i); // if a format was specified, break out. Otherwise, loop around until // all formats have been removed if (!clearall) break; } } // if the last format for an item is removed, remove the entire item if (!item.Length()) mItems.RemoveElementAt(aIndex); }
nsresult DataTransfer::GetDataAtInternal(const nsAString& aFormat, uint32_t aIndex, nsIPrincipal* aSubjectPrincipal, nsIVariant** aData) { *aData = nullptr; if (aFormat.IsEmpty()) { return NS_OK; } if (aIndex >= MozItemCount()) { return NS_ERROR_DOM_INDEX_SIZE_ERR; } // Only the first item is valid for clipboard events if (aIndex > 0 && (mEventMessage == eCut || mEventMessage == eCopy || mEventMessage == ePaste)) { return NS_ERROR_DOM_INDEX_SIZE_ERR; } nsAutoString format; GetRealFormat(aFormat, format); MOZ_ASSERT(aSubjectPrincipal); RefPtr<DataTransferItem> item = mItems->MozItemByTypeAt(format, aIndex); if (!item) { // The index exists but there's no data for the specified format, in this // case we just return undefined 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; } // DataTransferItem::Data() handles the principal checks ErrorResult result; nsCOMPtr<nsIVariant> data = item->Data(aSubjectPrincipal, result); if (NS_WARN_IF(!data || result.Failed())) { return result.StealNSResult(); } data.forget(aData); return NS_OK; }
void DataTransfer::MozClearDataAtHelper(const nsAString& aFormat, uint32_t aIndex, nsIPrincipal& aSubjectPrincipal, ErrorResult& aRv) { MOZ_ASSERT(!mReadOnly); MOZ_ASSERT(aIndex < MozItemCount()); MOZ_ASSERT(aIndex == 0 || (mEventMessage != eCut && mEventMessage != eCopy && mEventMessage != ePaste)); nsAutoString format; GetRealFormat(aFormat, format); mItems->MozRemoveByTypeAt(format, aIndex, aSubjectPrincipal, aRv); }
nsresult DataTransfer::SetDataWithPrincipal(const nsAString& aFormat, nsIVariant* aData, uint32_t aIndex, nsIPrincipal* aPrincipal) { nsAutoString format; GetRealFormat(aFormat, format); ErrorResult rv; RefPtr<DataTransferItem> item = mItems->SetDataWithPrincipal(format, aData, aIndex, aPrincipal, /* aInsertOnly = */ false, /* aHidden= */ false, rv); return rv.StealNSResult(); }
NS_IMETHODIMP nsDOMDataTransfer::MozClearDataAt(const nsAString& aFormat, PRUint32 aIndex) { if (mReadOnly) return NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR; if (aIndex >= mItems.Length()) return NS_ERROR_DOM_INDEX_SIZE_ERR; nsAutoString format; GetRealFormat(aFormat, format); nsresult rv = NS_OK; nsIPrincipal* principal = GetCurrentPrincipal(&rv); NS_ENSURE_SUCCESS(rv, rv); // if the format is empty, clear all formats PRBool clearall = format.IsEmpty(); nsTArray<TransferItem>& item = mItems[aIndex]; // count backwards so that the count and index don't have to be adjusted // after removing an element for (PRInt32 i = item.Length() - 1; i >= 0; i--) { TransferItem& formatitem = item[i]; if (clearall || formatitem.mFormat.Equals(format)) { // don't allow removing data that has a stronger principal PRBool subsumes; if (formatitem.mPrincipal && principal && (NS_FAILED(principal->Subsumes(formatitem.mPrincipal, &subsumes)) || !subsumes)) return NS_ERROR_DOM_SECURITY_ERR; item.RemoveElementAt(i); // if a format was specified, break out. Otherwise, loop around until // all formats have been removed if (!clearall) break; } } // if the last format for an item is removed, remove the entire item if (!item.Length()) mItems.RemoveElementAt(aIndex); return NS_OK; }
void DataTransfer::SetDataWithPrincipalFromOtherProcess(const nsAString& aFormat, nsIVariant* aData, uint32_t aIndex, nsIPrincipal* aPrincipal, bool aHidden) { if (aFormat.EqualsLiteral(kCustomTypesMime)) { FillInExternalCustomTypes(aData, aIndex, aPrincipal); } else { nsAutoString format; GetRealFormat(aFormat, format); ErrorResult rv; RefPtr<DataTransferItem> item = mItems->SetDataWithPrincipal(format, aData, aIndex, aPrincipal, /* aInsertOnly = */ false, aHidden, rv); if (NS_WARN_IF(rv.Failed())) { rv.SuppressException(); } } }
NS_IMETHODIMP DataTransfer::MozGetDataAt(const nsAString& aFormat, uint32_t aIndex, nsIVariant** aData) { *aData = nullptr; if (aFormat.IsEmpty()) return NS_OK; if (aIndex >= mItems.Length()) { return NS_ERROR_DOM_INDEX_SIZE_ERR; } // Only the first item is valid for clipboard events if (aIndex > 0 && (mEventType == NS_CUT || mEventType == NS_COPY || mEventType == NS_PASTE)) { return NS_ERROR_DOM_INDEX_SIZE_ERR; } nsAutoString format; GetRealFormat(aFormat, format); nsTArray<TransferItem>& item = mItems[aIndex]; // 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 // source of the drag is in a child frame of the caller. In that case, // we only allow access to data of the same principal. During other events, // only allow access to the data with the same principal. nsIPrincipal* principal = nullptr; if (mIsCrossDomainSubFrameDrop || (mEventType != NS_DRAGDROP_DROP && mEventType != NS_DRAGDROP_DRAGDROP && mEventType != NS_PASTE && !nsContentUtils::IsCallerChrome())) { principal = nsContentUtils::SubjectPrincipal(); } uint32_t count = item.Length(); for (uint32_t i = 0; i < count; i++) { TransferItem& formatitem = item[i]; if (formatitem.mFormat.Equals(format)) { bool subsumes; if (formatitem.mPrincipal && principal && (NS_FAILED(principal->Subsumes(formatitem.mPrincipal, &subsumes)) || !subsumes)) return NS_ERROR_DOM_SECURITY_ERR; if (!formatitem.mData) { FillInExternalData(formatitem, aIndex); } else { nsCOMPtr<nsISupports> data; formatitem.mData->GetAsISupports(getter_AddRefs(data)); // Make sure the code that is calling us is same-origin with the data. nsCOMPtr<EventTarget> pt = do_QueryInterface(data); if (pt) { nsresult rv = NS_OK; nsIScriptContext* c = pt->GetContextForEventHandlers(&rv); NS_ENSURE_TRUE(c && NS_SUCCEEDED(rv), NS_ERROR_DOM_SECURITY_ERR); nsIGlobalObject* go = c->GetGlobalObject(); NS_ENSURE_TRUE(go, NS_ERROR_DOM_SECURITY_ERR); nsCOMPtr<nsIScriptObjectPrincipal> sp = do_QueryInterface(go); MOZ_ASSERT(sp, "This cannot fail on the main thread."); nsIPrincipal* dataPrincipal = sp->GetPrincipal(); NS_ENSURE_TRUE(dataPrincipal, NS_ERROR_DOM_SECURITY_ERR); if (!principal) { principal = nsContentUtils::SubjectPrincipal(); } bool equals = false; NS_ENSURE_TRUE(NS_SUCCEEDED(principal->Equals(dataPrincipal, &equals)) && equals, NS_ERROR_DOM_SECURITY_ERR); } } *aData = formatitem.mData; NS_IF_ADDREF(*aData); return NS_OK; } } return NS_OK; }
nsresult DataTransfer::GetDataAtInternal(const nsAString& aFormat, uint32_t aIndex, nsIPrincipal* aSubjectPrincipal, nsIVariant** aData) { *aData = nullptr; if (aFormat.IsEmpty()) { return NS_OK; } if (aIndex >= mItems.Length()) { return NS_ERROR_DOM_INDEX_SIZE_ERR; } // Only the first item is valid for clipboard events if (aIndex > 0 && (mEventMessage == eCut || mEventMessage == eCopy || mEventMessage == ePaste)) { return NS_ERROR_DOM_INDEX_SIZE_ERR; } nsAutoString format; GetRealFormat(aFormat, format); nsTArray<TransferItem>& item = mItems[aIndex]; // If this is a content caller, and a file is in the data transfer, only // return the file type. if (!format.EqualsLiteral(kFileMime) && !nsContentUtils::IsSystemPrincipal(aSubjectPrincipal)) { uint32_t count = item.Length(); for (uint32_t i = 0; i < count; i++) { if (item[i].mFormat.EqualsLiteral(kFileMime)) { 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 // source of the drag is in a child frame of the caller. In that case, // we only allow access to data of the same principal. During other events, // only allow access to the data with the same principal. bool checkFormatItemPrincipal = mIsCrossDomainSubFrameDrop || (mEventMessage != eDrop && mEventMessage != eLegacyDragDrop && mEventMessage != ePaste); uint32_t count = item.Length(); for (uint32_t i = 0; i < count; i++) { TransferItem& formatitem = item[i]; if (formatitem.mFormat.Equals(format)) { if (formatitem.mPrincipal && checkFormatItemPrincipal && !aSubjectPrincipal->Subsumes(formatitem.mPrincipal)) { return NS_ERROR_DOM_SECURITY_ERR; } if (!formatitem.mData) { FillInExternalData(formatitem, aIndex); } else { nsCOMPtr<nsISupports> data; formatitem.mData->GetAsISupports(getter_AddRefs(data)); // Make sure the code that is calling us is same-origin with the data. nsCOMPtr<EventTarget> pt = do_QueryInterface(data); if (pt) { nsresult rv = NS_OK; nsIScriptContext* c = pt->GetContextForEventHandlers(&rv); NS_ENSURE_TRUE(c && NS_SUCCEEDED(rv), NS_ERROR_DOM_SECURITY_ERR); nsIGlobalObject* go = c->GetGlobalObject(); NS_ENSURE_TRUE(go, NS_ERROR_DOM_SECURITY_ERR); nsCOMPtr<nsIScriptObjectPrincipal> sp = do_QueryInterface(go); MOZ_ASSERT(sp, "This cannot fail on the main thread."); nsIPrincipal* dataPrincipal = sp->GetPrincipal(); NS_ENSURE_TRUE(dataPrincipal, NS_ERROR_DOM_SECURITY_ERR); NS_ENSURE_TRUE(aSubjectPrincipal->Subsumes(dataPrincipal), NS_ERROR_DOM_SECURITY_ERR); } } *aData = formatitem.mData; NS_IF_ADDREF(*aData); return NS_OK; } } return NS_OK; }
NS_IMETHODIMP nsDOMDataTransfer::MozGetDataAt(const nsAString& aFormat, PRUint32 aIndex, nsIVariant** aData) { *aData = nsnull; if (aFormat.IsEmpty()) return NS_OK; if (aIndex >= mItems.Length()) return NS_ERROR_DOM_INDEX_SIZE_ERR; nsAutoString format; GetRealFormat(aFormat, format); nsTArray<TransferItem>& item = mItems[aIndex]; // allow access to any data in the drop and dragdrop events, or if the // UniversalBrowserRead privilege is set, otherwise only allow access to // data from the same principal. nsIPrincipal* principal = nsnull; if (mEventType != NS_DRAGDROP_DROP && mEventType != NS_DRAGDROP_DRAGDROP && !nsContentUtils::IsCallerTrustedForCapability("UniversalBrowserRead")) { nsresult rv = NS_OK; principal = GetCurrentPrincipal(&rv); NS_ENSURE_SUCCESS(rv, rv); } PRUint32 count = item.Length(); for (PRUint32 i = 0; i < count; i++) { TransferItem& formatitem = item[i]; if (formatitem.mFormat.Equals(format)) { PRBool subsumes; if (formatitem.mPrincipal && principal && (NS_FAILED(principal->Subsumes(formatitem.mPrincipal, &subsumes)) || !subsumes)) return NS_ERROR_DOM_SECURITY_ERR; if (!formatitem.mData) { FillInExternalDragData(formatitem, aIndex); } else { nsCOMPtr<nsISupports> data; formatitem.mData->GetAsISupports(getter_AddRefs(data)); // Make sure the code that is calling us is same-origin with the data. nsCOMPtr<nsIDOMEventTarget> pt = do_QueryInterface(data); if (pt) { nsresult rv = NS_OK; nsIScriptContext* c = pt->GetContextForEventHandlers(&rv); NS_ENSURE_TRUE(c && NS_SUCCEEDED(rv), NS_ERROR_DOM_SECURITY_ERR); nsIScriptObjectPrincipal* sp = c->GetObjectPrincipal(); NS_ENSURE_TRUE(sp, NS_ERROR_DOM_SECURITY_ERR); nsIPrincipal* dataPrincipal = sp->GetPrincipal(); NS_ENSURE_TRUE(dataPrincipal, NS_ERROR_DOM_SECURITY_ERR); NS_ENSURE_TRUE(principal || (principal = GetCurrentPrincipal(&rv)), NS_ERROR_DOM_SECURITY_ERR); NS_ENSURE_SUCCESS(rv, rv); PRBool equals = PR_FALSE; NS_ENSURE_TRUE(NS_SUCCEEDED(principal->Equals(dataPrincipal, &equals)) && equals, NS_ERROR_DOM_SECURITY_ERR); } } *aData = formatitem.mData; NS_IF_ADDREF(*aData); return NS_OK; } } return NS_OK; }