/** * Changes the principal. Note that this will be called on the main thread, but * changes will be enacted on the MediaStreamGraph thread. If the principal * change results in the document principal losing access to the stream, then * there needs to be other measures in place to ensure that any media that is * governed by the new stream principal is not available to the MediaStreamGraph * before this change completes. Otherwise, a site could get access to * media that they are not authorized to receive. * * One solution is to block the altered content, call this method, then dispatch * another change request to the MediaStreamGraph thread that allows the content * under the new principal to flow. This might be unnecessary if the principal * change is changing to be the document principal. */ void MediaStreamAudioSourceNode::PrincipalChanged( MediaStreamTrack* aMediaStreamTrack) { MOZ_ASSERT(aMediaStreamTrack == mInputTrack); bool subsumes = false; Document* doc = nullptr; if (nsPIDOMWindowInner* parent = Context()->GetParentObject()) { doc = parent->GetExtantDoc(); if (doc) { nsIPrincipal* docPrincipal = doc->NodePrincipal(); nsIPrincipal* trackPrincipal = aMediaStreamTrack->GetPrincipal(); if (!trackPrincipal || NS_FAILED(docPrincipal->Subsumes(trackPrincipal, &subsumes))) { subsumes = false; } } } auto stream = static_cast<AudioNodeExternalInputStream*>(mStream.get()); bool enabled = subsumes || aMediaStreamTrack->GetCORSMode() != CORS_NONE; stream->SetInt32Parameter(MediaStreamAudioSourceNodeEngine::ENABLE, enabled); if (!enabled && doc) { nsContentUtils::ReportToConsole( nsIScriptError::warningFlag, NS_LITERAL_CSTRING("Web Audio"), doc, nsContentUtils::eDOM_PROPERTIES, CrossOriginErrorString()); } }
already_AddRefed<nsIPrincipal> PermissionStatus::GetPrincipal() const { nsCOMPtr<nsPIDOMWindowInner> window = GetOwner(); if (NS_WARN_IF(!window)) { return nullptr; } Document* doc = window->GetExtantDoc(); if (NS_WARN_IF(!doc)) { return nullptr; } nsCOMPtr<nsIPrincipal> principal = mozilla::BasePrincipal::Cast(doc->NodePrincipal()) ->CloneStrippingUserContextIdAndFirstPartyDomain(); NS_ENSURE_TRUE(principal, nullptr); return principal.forget(); }
/*static*/ already_AddRefed<Response> Response::Constructor( const GlobalObject& aGlobal, const Optional<Nullable<fetch::ResponseBodyInit>>& aBody, const ResponseInit& aInit, ErrorResult& aRv) { nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(aGlobal.GetAsSupports()); if (NS_WARN_IF(!global)) { aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR); return nullptr; } if (aInit.mStatus < 200 || aInit.mStatus > 599) { aRv.ThrowRangeError<MSG_INVALID_RESPONSE_STATUSCODE_ERROR>(); return nullptr; } // Check if the status text contains illegal characters nsACString::const_iterator start, end; aInit.mStatusText.BeginReading(start); aInit.mStatusText.EndReading(end); if (FindCharInReadable('\r', start, end)) { aRv.ThrowTypeError<MSG_RESPONSE_INVALID_STATUSTEXT_ERROR>(); return nullptr; } // Reset iterator since FindCharInReadable advances it. aInit.mStatusText.BeginReading(start); if (FindCharInReadable('\n', start, end)) { aRv.ThrowTypeError<MSG_RESPONSE_INVALID_STATUSTEXT_ERROR>(); return nullptr; } RefPtr<InternalResponse> internalResponse = new InternalResponse(aInit.mStatus, aInit.mStatusText); UniquePtr<mozilla::ipc::PrincipalInfo> principalInfo; // Grab a valid channel info from the global so this response is 'valid' for // interception. if (NS_IsMainThread()) { ChannelInfo info; nsCOMPtr<nsPIDOMWindowInner> window = do_QueryInterface(global); if (window) { Document* doc = window->GetExtantDoc(); MOZ_ASSERT(doc); info.InitFromDocument(doc); principalInfo.reset(new mozilla::ipc::PrincipalInfo()); nsresult rv = PrincipalToPrincipalInfo(doc->NodePrincipal(), principalInfo.get()); if (NS_WARN_IF(NS_FAILED(rv))) { aRv.ThrowTypeError<MSG_FETCH_BODY_CONSUMED_ERROR>(); return nullptr; } internalResponse->InitChannelInfo(info); } else if (nsContentUtils::IsSystemPrincipal(global->PrincipalOrNull())) { info.InitFromChromeGlobal(global); internalResponse->InitChannelInfo(info); } /** * The channel info is left uninitialized if neither the above `if` nor * `else if` statements are executed; this could be because we're in a * WebExtensions content script, where the global (i.e. `global`) is a * wrapper, and the principal is an expanded principal. In this case, * as far as I can tell, there's no way to get the security info, but we'd * like the `Response` to be successfully constructed. */ } else { WorkerPrivate* worker = GetCurrentThreadWorkerPrivate(); MOZ_ASSERT(worker); internalResponse->InitChannelInfo(worker->GetChannelInfo()); principalInfo = MakeUnique<mozilla::ipc::PrincipalInfo>(worker->GetPrincipalInfo()); } internalResponse->SetPrincipalInfo(std::move(principalInfo)); RefPtr<Response> r = new Response(global, internalResponse, nullptr); if (aInit.mHeaders.WasPassed()) { internalResponse->Headers()->Clear(); // Instead of using Fill, create an object to allow the constructor to // unwrap the HeadersInit. RefPtr<Headers> headers = Headers::Create(global, aInit.mHeaders.Value(), aRv); if (aRv.Failed()) { return nullptr; } internalResponse->Headers()->Fill(*headers->GetInternalHeaders(), aRv); if (NS_WARN_IF(aRv.Failed())) { return nullptr; } } if (aBody.WasPassed() && !aBody.Value().IsNull()) { if (aInit.mStatus == 204 || aInit.mStatus == 205 || aInit.mStatus == 304) { aRv.ThrowTypeError<MSG_RESPONSE_NULL_STATUS_WITH_BODY>(); return nullptr; } nsCString contentTypeWithCharset; nsCOMPtr<nsIInputStream> bodyStream; int64_t bodySize = InternalResponse::UNKNOWN_BODY_SIZE; const fetch::ResponseBodyInit& body = aBody.Value().Value(); if (body.IsReadableStream()) { aRv.MightThrowJSException(); JSContext* cx = aGlobal.Context(); const ReadableStream& readableStream = body.GetAsReadableStream(); JS::Rooted<JSObject*> readableStreamObj(cx, readableStream.Obj()); bool disturbed; bool locked; if (!JS::ReadableStreamIsDisturbed(cx, readableStreamObj, &disturbed) || !JS::ReadableStreamIsLocked(cx, readableStreamObj, &locked)) { aRv.StealExceptionFromJSContext(cx); return nullptr; } if (disturbed || locked) { aRv.ThrowTypeError<MSG_FETCH_BODY_CONSUMED_ERROR>(); return nullptr; } r->SetReadableStreamBody(cx, readableStreamObj); JS::ReadableStreamMode streamMode; if (!JS::ReadableStreamGetMode(cx, readableStreamObj, &streamMode)) { aRv.StealExceptionFromJSContext(cx); return nullptr; } if (streamMode == JS::ReadableStreamMode::ExternalSource) { // If this is a DOM generated ReadableStream, we can extract the // inputStream directly. JS::ReadableStreamUnderlyingSource* underlyingSource = nullptr; if (!JS::ReadableStreamGetExternalUnderlyingSource( cx, readableStreamObj, &underlyingSource)) { aRv.StealExceptionFromJSContext(cx); return nullptr; } MOZ_ASSERT(underlyingSource); aRv = FetchStream::RetrieveInputStream(underlyingSource, getter_AddRefs(bodyStream)); // The releasing of the external source is needed in order to avoid an // extra stream lock. if (!JS::ReadableStreamReleaseExternalUnderlyingSource( cx, readableStreamObj)) { aRv.StealExceptionFromJSContext(cx); return nullptr; } if (NS_WARN_IF(aRv.Failed())) { return nullptr; } } else { // If this is a JS-created ReadableStream, let's create a // FetchStreamReader. aRv = FetchStreamReader::Create(aGlobal.Context(), global, getter_AddRefs(r->mFetchStreamReader), getter_AddRefs(bodyStream)); if (NS_WARN_IF(aRv.Failed())) { return nullptr; } } } else { uint64_t size = 0; aRv = ExtractByteStreamFromBody(body, getter_AddRefs(bodyStream), contentTypeWithCharset, size); if (NS_WARN_IF(aRv.Failed())) { return nullptr; } bodySize = size; } internalResponse->SetBody(bodyStream, bodySize); if (!contentTypeWithCharset.IsVoid() && !internalResponse->Headers()->Has(NS_LITERAL_CSTRING("Content-Type"), aRv)) { // Ignore Append() failing here. ErrorResult error; internalResponse->Headers()->Append(NS_LITERAL_CSTRING("Content-Type"), contentTypeWithCharset, error); error.SuppressException(); } if (aRv.Failed()) { return nullptr; } } r->SetMimeType(); return r.forget(); }