NS_IMETHODIMP nsDOMDataTransfer::MozSetDataAt(const nsAString& aFormat, nsIVariant* aData, PRUint32 aIndex) { NS_ENSURE_TRUE(aData, NS_ERROR_NULL_POINTER); if (aFormat.IsEmpty()) return NS_OK; if (mReadOnly) return NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR; // Specifying an index less than the current length will replace an existing // item. Specifying an index equal to the current length will add a new item. if (aIndex > mItems.Length()) return NS_ERROR_DOM_INDEX_SIZE_ERR; // don't allow non-chrome to add file data // XXX perhaps this should also limit any non-string type as well if ((aFormat.EqualsLiteral("application/x-moz-file-promise") || aFormat.EqualsLiteral("application/x-moz-file")) && !nsContentUtils::IsCallerTrustedForCapability("UniversalXPConnect")) { return NS_ERROR_DOM_SECURITY_ERR; } nsresult rv = NS_OK; nsIPrincipal* principal = GetCurrentPrincipal(&rv); NS_ENSURE_SUCCESS(rv, rv); return SetDataWithPrincipal(aFormat, aData, aIndex, principal); }
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); }
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; }
NS_IMETHODIMP DataTransfer::MozSetDataAt(const nsAString& aFormat, nsIVariant* aData, uint32_t aIndex) { if (aFormat.IsEmpty()) { return NS_OK; } if (mReadOnly) { return NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR; } // Specifying an index less than the current length will replace an existing // item. Specifying an index equal to the current length will add a new item. 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; } // don't allow non-chrome to add file data // XXX perhaps this should also limit any non-string type as well if ((aFormat.EqualsLiteral("application/x-moz-file-promise") || aFormat.EqualsLiteral("application/x-moz-file")) && !nsContentUtils::IsCallerChrome()) { return NS_ERROR_DOM_SECURITY_ERR; } nsresult rv = NS_OK; nsIPrincipal* principal = GetCurrentPrincipal(&rv); NS_ENSURE_SUCCESS(rv, rv); return SetDataWithPrincipal(aFormat, aData, aIndex, principal); }
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())) { nsresult rv = NS_OK; principal = GetCurrentPrincipal(&rv); NS_ENSURE_SUCCESS(rv, rv); } 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); NS_ENSURE_TRUE(principal || (principal = GetCurrentPrincipal(&rv)), NS_ERROR_DOM_SECURITY_ERR); NS_ENSURE_SUCCESS(rv, rv); 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; }
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; }