diff options
author | Jonathan Kingston <jonathan@jooped.co.uk> | 2020-11-24 02:06:08 +0000 |
---|---|---|
committer | Jonathan Kingston <jonathan@jooped.co.uk> | 2020-11-25 18:30:50 +0000 |
commit | 0e1479cc847333c81a37d11f0f65f0304972ba3c (patch) | |
tree | c2f505ce162f481639d9115f19ba96421c552253 /components/script/dom | |
parent | 20ef49e035596136ce43b47a66b27c8b5c25967b (diff) | |
download | servo-0e1479cc847333c81a37d11f0f65f0304972ba3c.tar.gz servo-0e1479cc847333c81a37d11f0f65f0304972ba3c.zip |
Add creation url and Secure Contexts
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> |