mirror of
https://github.com/servo/servo.git
synced 2025-08-04 13:10:20 +01:00
Add creation url and Secure Contexts
This commit is contained in:
parent
20ef49e035
commit
0e1479cc84
25 changed files with 207 additions and 9 deletions
|
@ -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 '')
|
||||
|
|
|
@ -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,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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(),
|
||||
|
|
|
@ -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>() {
|
||||
|
|
|
@ -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 || {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -216,6 +216,8 @@ struct InProgressLoad {
|
|||
canceller: FetchCanceller,
|
||||
/// Flag for sharing with the layout thread that is not yet created.
|
||||
layout_is_busy: Arc<AtomicBool>,
|
||||
/// If inheriting the security context
|
||||
inherited_secure_context: Option<bool>,
|
||||
}
|
||||
|
||||
impl InProgressLoad {
|
||||
|
@ -231,6 +233,7 @@ impl InProgressLoad {
|
|||
url: ServoUrl,
|
||||
origin: MutableOrigin,
|
||||
layout_is_busy: Arc<AtomicBool>,
|
||||
inherited_secure_context: Option<bool>,
|
||||
) -> InProgressLoad {
|
||||
let current_time = get_time();
|
||||
let navigation_start_precise = precise_time_ns();
|
||||
|
@ -253,6 +256,7 @@ impl InProgressLoad {
|
|||
navigation_start_precise: navigation_start_precise,
|
||||
canceller: Default::default(),
|
||||
layout_is_busy: layout_is_busy,
|
||||
inherited_secure_context: inherited_secure_context,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -692,6 +696,9 @@ pub struct ScriptThread {
|
|||
|
||||
/// Receiver to receive commands from optional WebGPU server.
|
||||
webgpu_port: RefCell<Option<Receiver<WebGPUMsg>>>,
|
||||
|
||||
// Secure context
|
||||
inherited_secure_context: Option<bool>,
|
||||
}
|
||||
|
||||
struct BHMExitSignal {
|
||||
|
@ -778,6 +785,7 @@ impl ScriptThreadFactory for ScriptThread {
|
|||
let top_level_browsing_context_id = state.top_level_browsing_context_id;
|
||||
let parent_info = state.parent_info;
|
||||
let opener = state.opener;
|
||||
let secure = load_data.inherited_secure_context.clone();
|
||||
let mem_profiler_chan = state.mem_profiler_chan.clone();
|
||||
let window_size = state.window_size;
|
||||
let layout_is_busy = state.layout_is_busy.clone();
|
||||
|
@ -816,6 +824,7 @@ impl ScriptThreadFactory for ScriptThread {
|
|||
load_data.url.clone(),
|
||||
origin,
|
||||
layout_is_busy,
|
||||
secure,
|
||||
);
|
||||
script_thread.pre_page_load(new_load, load_data);
|
||||
|
||||
|
@ -1149,6 +1158,7 @@ impl ScriptThread {
|
|||
is_headless: script_thread.headless,
|
||||
user_agent: script_thread.user_agent.clone(),
|
||||
gpu_id_hub: script_thread.gpu_id_hub.clone(),
|
||||
inherited_secure_context: script_thread.inherited_secure_context.clone(),
|
||||
};
|
||||
Rc::new(WorkletThreadPool::spawn(init))
|
||||
})
|
||||
|
@ -1404,6 +1414,7 @@ impl ScriptThread {
|
|||
is_user_interacting: Cell::new(false),
|
||||
gpu_id_hub: Arc::new(Mutex::new(Identities::new())),
|
||||
webgpu_port: RefCell::new(None),
|
||||
inherited_secure_context: state.inherited_secure_context,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2523,6 +2534,7 @@ impl ScriptThread {
|
|||
load_data.url.clone(),
|
||||
origin,
|
||||
layout_is_busy.clone(),
|
||||
load_data.inherited_secure_context.clone(),
|
||||
);
|
||||
if load_data.url.as_str() == "about:blank" {
|
||||
self.start_page_load_about_blank(new_load, load_data.js_eval_result);
|
||||
|
@ -3271,6 +3283,7 @@ impl ScriptThread {
|
|||
incomplete.parent_info,
|
||||
incomplete.window_size,
|
||||
origin.clone(),
|
||||
final_url.clone(),
|
||||
incomplete.navigation_start,
|
||||
incomplete.navigation_start_precise,
|
||||
self.webgl_chan.as_ref().map(|chan| chan.channel()),
|
||||
|
@ -3290,6 +3303,7 @@ impl ScriptThread {
|
|||
self.player_context.clone(),
|
||||
self.event_loop_waker.as_ref().map(|w| (*w).clone_box()),
|
||||
self.gpu_id_hub.clone(),
|
||||
incomplete.inherited_secure_context,
|
||||
);
|
||||
|
||||
// Initialize the browsing context for the window.
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue