diff options
author | bors-servo <servo-ops@mozilla.com> | 2020-11-25 18:32:58 -0500 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-11-25 18:32:58 -0500 |
commit | cf68cd16bda1c0b2547228112920289fd373f2bd (patch) | |
tree | f3ceb1aafd0f35085b7e389b39c27382d94308ab /components/script/dom | |
parent | 20ef49e035596136ce43b47a66b27c8b5c25967b (diff) | |
parent | 80902ee716564f0d8abe039b8fb44c14eaf087c9 (diff) | |
download | servo-cf68cd16bda1c0b2547228112920289fd373f2bd.tar.gz servo-cf68cd16bda1c0b2547228112920289fd373f2bd.zip |
Auto merge of #27806 - jonathanKingston:secure-contexts-with-creation-url, r=jdm
Add creation url and Secure Contexts
A more complete version of https://github.com/servo/servo/pull/27793
I've added in creation/creator URLs to match the HTML spec for the "global settings object" which doesn't exist in Servo but lots of its concepts exist within the Global Scope.
This fixes the previously mentioned blob url test fails but has the previously mentioned issues in https://github.com/servo/servo/pull/27793
---
<!-- Thank you for contributing to Servo! Please replace each `[ ]` by `[X]` when the step is complete, and replace `___` with appropriate data: -->
- [ ] `./mach build -d` does not report any errors
- [ ] `./mach test-tidy` does not report any errors
- [ ] These changes fix #___ (GitHub issue number if applicable)
<!-- Either: -->
- [ ] There are tests for these changes OR
- [ ] These changes do not require tests because ___
<!-- Also, please make sure that "Allow edits from maintainers" checkbox is checked, so that we can help you if you get stuck somewhere along the way.-->
<!-- Pull requests that do not address these steps are welcome, but they will require additional verification as part of the review process. -->
Diffstat (limited to 'components/script/dom')
-rw-r--r-- | components/script/dom/bindings/codegen/CodegenRust.py | 13 | ||||
-rw-r--r-- | components/script/dom/bindings/guard.rs | 12 | ||||
-rw-r--r-- | components/script/dom/dissimilaroriginwindow.rs | 2 | ||||
-rw-r--r-- | components/script/dom/globalscope.rs | 28 | ||||
-rw-r--r-- | components/script/dom/htmlanchorelement.rs | 2 | ||||
-rw-r--r-- | components/script/dom/htmlformelement.rs | 1 | ||||
-rw-r--r-- | components/script/dom/htmliframeelement.rs | 4 | ||||
-rw-r--r-- | components/script/dom/location.rs | 1 | ||||
-rw-r--r-- | components/script/dom/webidls/WindowOrWorkerGlobalScope.webidl | 5 | ||||
-rw-r--r-- | components/script/dom/window.rs | 8 | ||||
-rw-r--r-- | components/script/dom/windowproxy.rs | 3 | ||||
-rw-r--r-- | components/script/dom/workerglobalscope.rs | 9 | ||||
-rw-r--r-- | components/script/dom/workletglobalscope.rs | 4 |
13 files changed, 88 insertions, 4 deletions
diff --git a/components/script/dom/bindings/codegen/CodegenRust.py b/components/script/dom/bindings/codegen/CodegenRust.py index 83e68cdce76..13c295ef1a2 100644 --- a/components/script/dom/bindings/codegen/CodegenRust.py +++ b/components/script/dom/bindings/codegen/CodegenRust.py @@ -1517,7 +1517,7 @@ def getRetvalDeclarationForType(returnType, descriptorProvider): returnType) -def MemberCondition(pref, func, exposed): +def MemberCondition(pref, func, exposed, secure): """ A string representing the condition for a member to actually be exposed. Any of the arguments can be None. If not None, they should have the @@ -1526,11 +1526,14 @@ def MemberCondition(pref, func, exposed): pref: The name of the preference. func: The name of the function. exposed: One or more names of an exposed global. + secure: Requires secure context. """ assert pref is None or isinstance(pref, str) assert func is None or isinstance(func, str) assert exposed is None or isinstance(exposed, set) - assert func is None or pref is None or exposed is None + assert func is None or pref is None or exposed is None or secure is None + if secure: + return 'Condition::SecureContext()' if pref: return 'Condition::Pref("%s")' % pref if func: @@ -1580,7 +1583,8 @@ class PropertyDefiner: "Pref"), PropertyDefiner.getStringAttr(interfaceMember, "Func"), - interfaceMember.exposureSet) + interfaceMember.exposureSet, + interfaceMember.getExtendedAttribute("SecureContext")) def generateGuardedArray(self, array, name, specTemplate, specTerminator, specType, getCondition, getDataTuple): @@ -3038,7 +3042,7 @@ let global = incumbent_global.reflector().get_jsobject();\n""" for m in interface.members: if m.isAttr() and not m.isStatic() and m.type.isJSONType(): name = m.identifier.name - conditions = MemberCondition(None, None, m.exposureSet) + conditions = MemberCondition(None, None, m.exposureSet, None) ret_conditions = '&[' + ", ".join(conditions) + "]" ret += fill( """ @@ -7838,6 +7842,7 @@ impl %(base)s { if PropertyDefiner.getStringAttr(m, 'Pref') or \ PropertyDefiner.getStringAttr(m, 'Func') or \ PropertyDefiner.getStringAttr(m, 'Exposed') or \ + m.getExtendedAttribute('SecureContext') or \ (m.isMethod() and m.isIdentifierLess()): continue display = m.identifier.name + ('()' if m.isMethod() else '') diff --git a/components/script/dom/bindings/guard.rs b/components/script/dom/bindings/guard.rs index 188d36fee17..17f3a3d20bc 100644 --- a/components/script/dom/bindings/guard.rs +++ b/components/script/dom/bindings/guard.rs @@ -6,6 +6,9 @@ use crate::dom::bindings::codegen::InterfaceObjectMap; use crate::dom::bindings::interface::is_exposed_in; +use crate::dom::globalscope::GlobalScope; +use crate::realms::AlreadyInRealm; +use crate::realms::InRealm; use crate::script_runtime::JSContext; use js::rust::HandleObject; use servo_config::prefs; @@ -45,16 +48,25 @@ pub enum Condition { Pref(&'static str), // The condition is satisfied if the interface is exposed in the global. Exposed(InterfaceObjectMap::Globals), + SecureContext(), /// The condition is always satisfied. Satisfied, } +fn is_secure_context(cx: JSContext) -> bool { + unsafe { + let in_realm_proof = AlreadyInRealm::assert_for_cx(JSContext::from_ptr(*cx)); + GlobalScope::from_context(*cx, InRealm::Already(&in_realm_proof)).is_secure_context() + } +} + impl Condition { pub fn is_satisfied(&self, cx: JSContext, obj: HandleObject, global: HandleObject) -> bool { match *self { Condition::Pref(name) => prefs::pref_map().get(name).as_bool().unwrap_or(false), Condition::Func(f) => f(cx, obj), Condition::Exposed(globals) => is_exposed_in(global, globals), + Condition::SecureContext() => is_secure_context(cx), Condition::Satisfied => true, } } diff --git a/components/script/dom/dissimilaroriginwindow.rs b/components/script/dom/dissimilaroriginwindow.rs index c00b08effe6..989aec3ff3d 100644 --- a/components/script/dom/dissimilaroriginwindow.rs +++ b/components/script/dom/dissimilaroriginwindow.rs @@ -57,12 +57,14 @@ impl DissimilarOriginWindow { global_to_clone_from.scheduler_chan().clone(), global_to_clone_from.resource_threads().clone(), global_to_clone_from.origin().clone(), + global_to_clone_from.creation_url().clone(), // FIXME(nox): The microtask queue is probably not important // here, but this whole DOM interface is a hack anyway. global_to_clone_from.microtask_queue().clone(), global_to_clone_from.is_headless(), global_to_clone_from.get_user_agent(), global_to_clone_from.wgpu_id_hub(), + Some(global_to_clone_from.is_secure_context()), ), window_proxy: Dom::from_ref(window_proxy), location: Default::default(), diff --git a/components/script/dom/globalscope.rs b/components/script/dom/globalscope.rs index 56adc2b8d90..6e576c036f7 100644 --- a/components/script/dom/globalscope.rs +++ b/components/script/dom/globalscope.rs @@ -246,6 +246,9 @@ pub struct GlobalScope { /// The origin of the globalscope origin: MutableOrigin, + /// https://html.spec.whatwg.org/multipage/#concept-environment-creation-url + creation_url: Option<ServoUrl>, + /// A map for storing the previous permission state read results. permission_state_invocation_results: DomRefCell<HashMap<String, PermissionState>>, @@ -309,6 +312,9 @@ pub struct GlobalScope { /// List of ongoing dynamic module imports. dynamic_modules: DomRefCell<DynamicModuleList>, + + /// Is considered in a secure context + inherited_secure_context: Option<bool>, } /// A wrapper for glue-code between the ipc router and the event-loop. @@ -719,10 +725,12 @@ impl GlobalScope { scheduler_chan: IpcSender<TimerSchedulerMsg>, resource_threads: ResourceThreads, origin: MutableOrigin, + creation_url: Option<ServoUrl>, microtask_queue: Rc<MicrotaskQueue>, is_headless: bool, user_agent: Cow<'static, str>, gpu_id_hub: Arc<Mutex<Identities>>, + inherited_secure_context: Option<bool>, ) -> Self { Self { message_port_state: DomRefCell::new(MessagePortState::UnManaged), @@ -747,6 +755,7 @@ impl GlobalScope { timers: OneshotTimers::new(scheduler_chan), init_timers: Default::default(), origin, + creation_url, permission_state_invocation_results: Default::default(), microtask_queue, list_auto_close_worker: Default::default(), @@ -761,6 +770,7 @@ impl GlobalScope { https_state: Cell::new(HttpsState::None), console_group_stack: DomRefCell::new(Vec::new()), dynamic_modules: DomRefCell::new(DynamicModuleList::new()), + inherited_secure_context, } } @@ -2311,6 +2321,11 @@ impl GlobalScope { &self.origin } + /// Get the creation_url for this global scope + pub fn creation_url(&self) -> &Option<ServoUrl> { + &self.creation_url + } + pub fn image_cache(&self) -> Arc<dyn ImageCache> { if let Some(window) = self.downcast::<Window>() { return window.image_cache(); @@ -2994,6 +3009,19 @@ impl GlobalScope { self.https_state.set(https_state); } + pub fn is_secure_context(&self) -> bool { + if Some(false) == self.inherited_secure_context { + return false; + } + if let Some(creation_url) = self.creation_url() { + if creation_url.scheme() == "blob" && Some(true) == self.inherited_secure_context { + return true; + } + return creation_url.is_potentially_trustworthy(); + } + false + } + /// https://www.w3.org/TR/CSP/#get-csp-of-object pub fn get_csp_list(&self) -> Option<CspList> { if let Some(window) = self.downcast::<Window>() { diff --git a/components/script/dom/htmlanchorelement.rs b/components/script/dom/htmlanchorelement.rs index be246203121..e6583329880 100644 --- a/components/script/dom/htmlanchorelement.rs +++ b/components/script/dom/htmlanchorelement.rs @@ -703,12 +703,14 @@ pub fn follow_hyperlink(subject: &Element, hyperlink_suffix: Option<String>) { // Step 14 let pipeline_id = target_window.upcast::<GlobalScope>().pipeline_id(); + let secure = target_window.upcast::<GlobalScope>().is_secure_context(); let load_data = LoadData::new( LoadOrigin::Script(document.origin().immutable().clone()), url, Some(pipeline_id), referrer, referrer_policy, + Some(secure), ); let target = Trusted::new(target_window); let task = task!(navigate_follow_hyperlink: move || { diff --git a/components/script/dom/htmlformelement.rs b/components/script/dom/htmlformelement.rs index a4df1059a0c..d06fd85a426 100644 --- a/components/script/dom/htmlformelement.rs +++ b/components/script/dom/htmlformelement.rs @@ -811,6 +811,7 @@ impl HTMLFormElement { None, target_window.upcast::<GlobalScope>().get_referrer(), target_document.get_referrer_policy(), + Some(target_window.upcast::<GlobalScope>().is_secure_context()), ); // Step 22 diff --git a/components/script/dom/htmliframeelement.rs b/components/script/dom/htmliframeelement.rs index 345e815ee50..6f5264999be 100644 --- a/components/script/dom/htmliframeelement.rs +++ b/components/script/dom/htmliframeelement.rs @@ -170,6 +170,7 @@ impl HTMLIFrameElement { top_level_browsing_context_id: top_level_browsing_context_id, new_pipeline_id: new_pipeline_id, is_private: false, // FIXME + inherited_secure_context: load_data.inherited_secure_context, replace: replace, }; @@ -244,6 +245,7 @@ impl HTMLIFrameElement { pipeline_id, window.upcast::<GlobalScope>().get_referrer(), document.get_referrer_policy(), + Some(window.upcast::<GlobalScope>().is_secure_context()), ); let element = self.upcast::<Element>(); load_data.srcdoc = String::from(element.get_string_attribute(&local_name!("srcdoc"))); @@ -327,6 +329,7 @@ impl HTMLIFrameElement { creator_pipeline_id, window.upcast::<GlobalScope>().get_referrer(), document.get_referrer_policy(), + Some(window.upcast::<GlobalScope>().is_secure_context()), ); let pipeline_id = self.pipeline_id(); @@ -354,6 +357,7 @@ impl HTMLIFrameElement { pipeline_id, window.upcast::<GlobalScope>().get_referrer(), document.get_referrer_policy(), + Some(window.upcast::<GlobalScope>().is_secure_context()), ); let browsing_context_id = BrowsingContextId::new(); let top_level_browsing_context_id = window.window_proxy().top_level_browsing_context_id(); diff --git a/components/script/dom/location.rs b/components/script/dom/location.rs index 48e8ea0c744..42e3a5846f3 100644 --- a/components/script/dom/location.rs +++ b/components/script/dom/location.rs @@ -52,6 +52,7 @@ impl Location { Some(pipeline_id), referrer, referrer_policy, + None, // Top navigation doesn't inherit secure context ); // TODO: rethrow exceptions, set exceptions enabled flag. self.window diff --git a/components/script/dom/webidls/WindowOrWorkerGlobalScope.webidl b/components/script/dom/webidls/WindowOrWorkerGlobalScope.webidl index 97b36721f8b..2ab8ba2c25d 100644 --- a/components/script/dom/webidls/WindowOrWorkerGlobalScope.webidl +++ b/components/script/dom/webidls/WindowOrWorkerGlobalScope.webidl @@ -36,5 +36,10 @@ partial interface mixin WindowOrWorkerGlobalScope { readonly attribute Performance performance; }; +// https://w3c.github.io/webappsec-secure-contexts/#monkey-patching-global-object +partial interface mixin WindowOrWorkerGlobalScope { + readonly attribute boolean isSecureContext; +}; + Window includes WindowOrWorkerGlobalScope; WorkerGlobalScope includes WindowOrWorkerGlobalScope; diff --git a/components/script/dom/window.rs b/components/script/dom/window.rs index 09497c0798a..70734efb9bb 100644 --- a/components/script/dom/window.rs +++ b/components/script/dom/window.rs @@ -1381,6 +1381,10 @@ impl WindowMethods for Window { } rval.get() } + + fn IsSecureContext(&self) -> bool { + self.upcast::<GlobalScope>().is_secure_context() + } } impl Window { @@ -2357,6 +2361,7 @@ impl Window { parent_info: Option<PipelineId>, window_size: WindowSizeData, origin: MutableOrigin, + creator_url: ServoUrl, navigation_start: u64, navigation_start_precise: u64, webgl_chan: Option<WebGLChan>, @@ -2376,6 +2381,7 @@ impl Window { player_context: WindowGLContext, event_loop_waker: Option<Box<dyn EventLoopWaker>>, gpu_id_hub: Arc<ParkMutex<Identities>>, + inherited_secure_context: Option<bool>, ) -> DomRoot<Self> { let layout_rpc: Box<dyn LayoutRPC + Send> = { let (rpc_send, rpc_recv) = unbounded(); @@ -2396,10 +2402,12 @@ impl Window { scheduler_chan, resource_threads, origin, + Some(creator_url), microtask_queue, is_headless, user_agent, gpu_id_hub, + inherited_secure_context, ), script_chan, task_manager, diff --git a/components/script/dom/windowproxy.rs b/components/script/dom/windowproxy.rs index 8be356e5ea2..e37e561af06 100644 --- a/components/script/dom/windowproxy.rs +++ b/components/script/dom/windowproxy.rs @@ -307,6 +307,7 @@ impl WindowProxy { None, document.global().get_referrer(), document.get_referrer_policy(), + None, // Doesn't inherit secure context ); let load_info = AuxiliaryBrowsingContextLoadInfo { load_data: load_data.clone(), @@ -511,12 +512,14 @@ impl WindowProxy { // Step 14.5 let referrer_policy = target_document.get_referrer_policy(); let pipeline_id = target_window.upcast::<GlobalScope>().pipeline_id(); + let secure = target_window.upcast::<GlobalScope>().is_secure_context(); let load_data = LoadData::new( LoadOrigin::Script(existing_document.origin().immutable().clone()), url, Some(pipeline_id), referrer, referrer_policy, + Some(secure), ); let replacement_flag = if new { HistoryEntryReplacement::Enabled diff --git a/components/script/dom/workerglobalscope.rs b/components/script/dom/workerglobalscope.rs index aabda0ab248..6092b3c4c3e 100644 --- a/components/script/dom/workerglobalscope.rs +++ b/components/script/dom/workerglobalscope.rs @@ -80,8 +80,10 @@ pub fn prepare_workerscope_init( worker_id: worker_id.unwrap_or_else(|| WorkerId(Uuid::new_v4())), pipeline_id: global.pipeline_id(), origin: global.origin().immutable().clone(), + creation_url: global.creation_url().clone(), is_headless: global.is_headless(), user_agent: global.get_user_agent(), + inherited_secure_context: Some(global.is_secure_context()), }; init @@ -141,10 +143,12 @@ impl WorkerGlobalScope { init.scheduler_chan, init.resource_threads, MutableOrigin::new(init.origin), + init.creation_url, runtime.microtask_queue.clone(), init.is_headless, init.user_agent, gpu_id_hub, + init.inherited_secure_context, ), worker_id: init.worker_id, worker_name, @@ -405,6 +409,11 @@ impl WorkerGlobalScopeMethods for WorkerGlobalScope { .ascii_serialization(), ) } + + // https://w3c.github.io/webappsec-secure-contexts/#dom-windoworworkerglobalscope-issecurecontext + fn IsSecureContext(&self) -> bool { + self.upcast::<GlobalScope>().is_secure_context() + } } impl WorkerGlobalScope { diff --git a/components/script/dom/workletglobalscope.rs b/components/script/dom/workletglobalscope.rs index 47e6315c940..29d5b9b7f99 100644 --- a/components/script/dom/workletglobalscope.rs +++ b/components/script/dom/workletglobalscope.rs @@ -71,10 +71,12 @@ impl WorkletGlobalScope { init.scheduler_chan.clone(), init.resource_threads.clone(), MutableOrigin::new(ImmutableOrigin::new_opaque()), + None, Default::default(), init.is_headless, init.user_agent.clone(), init.gpu_id_hub.clone(), + init.inherited_secure_context, ), base_url, to_script_thread_sender: init.to_script_thread_sender.clone(), @@ -166,6 +168,8 @@ pub struct WorkletGlobalScopeInit { pub user_agent: Cow<'static, str>, /// Identity manager for WebGPU resources pub gpu_id_hub: Arc<Mutex<Identities>>, + /// Is considered secure + pub inherited_secure_context: Option<bool>, } /// <https://drafts.css-houdini.org/worklets/#worklet-global-scope-type> |