already_AddRefed<nsIVariant> DataTransferItem::DataNoSecurityCheck() { if (!mData) { FillInExternalData(); } nsCOMPtr<nsIVariant> data = mData; return data.forget(); }
void DataTransfer::FillInExternalCustomTypes(uint32_t aIndex, nsIPrincipal* aPrincipal) { TransferItem item; item.mFormat.AssignLiteral(kCustomTypesMime); FillInExternalData(item, aIndex); if (!item.mData) { return; } FillInExternalCustomTypes(item.mData, aIndex, aPrincipal); }
void DataTransfer::FillAllExternalData() { if (mIsExternal) { for (uint32_t i = 0; i < mItems.Length(); ++i) { nsTArray<TransferItem>& itemArray = mItems[i]; for (uint32_t j = 0; j < itemArray.Length(); ++j) { if (!itemArray[j].mData) { FillInExternalData(itemArray[j], i); } } } } }
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; }