mirror of
https://github.com/tauri-apps/tauri.git
synced 2026-01-31 00:35:19 +01:00
Co-authored-by: Lucas Nogueira <118899497+lucasfernog-crabnebula@users.noreply.github.com> Co-authored-by: Lucas Nogueira <lucas@tauri.studio>
This commit is contained in:
8
.changes/windows-http-scheme.md
Normal file
8
.changes/windows-http-scheme.md
Normal file
@@ -0,0 +1,8 @@
|
||||
---
|
||||
'tauri': 'patch:enhance'
|
||||
'tauri-runtime': 'patch:enhance'
|
||||
'tauri-runtime-wry': 'patch:enhance'
|
||||
'tauri-utils': 'patch:enhance'
|
||||
---
|
||||
|
||||
Add setting to switch to `http://<scheme>.localhost/` for custom protocols on Windows.
|
||||
@@ -167,6 +167,7 @@
|
||||
"security": {
|
||||
"dangerousDisableAssetCspModification": false,
|
||||
"dangerousRemoteDomainIpcAccess": [],
|
||||
"dangerousUseHttpScheme": false,
|
||||
"freezePrototype": false
|
||||
},
|
||||
"updater": {
|
||||
@@ -423,6 +424,7 @@
|
||||
"default": {
|
||||
"dangerousDisableAssetCspModification": false,
|
||||
"dangerousRemoteDomainIpcAccess": [],
|
||||
"dangerousUseHttpScheme": false,
|
||||
"freezePrototype": false
|
||||
},
|
||||
"allOf": [
|
||||
@@ -2740,6 +2742,11 @@
|
||||
"items": {
|
||||
"$ref": "#/definitions/RemoteDomainAccessScope"
|
||||
}
|
||||
},
|
||||
"dangerousUseHttpScheme": {
|
||||
"description": "Sets whether the custom protocols should use `http://<scheme>.localhost` instead of the default `https://<scheme>.localhost` on Windows.\n\n**WARNING:** Using a `http` scheme will allow mixed content when trying to fetch `http` endpoints and is therefore less secure but will match the behavior of the `<scheme>://localhost` protocols used on macOS and Linux.",
|
||||
"default": false,
|
||||
"type": "boolean"
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
|
||||
@@ -3196,6 +3196,11 @@ fn create_webview<T: UserEvent>(
|
||||
});
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
{
|
||||
webview_builder = webview_builder.with_https_scheme(!pending.http_scheme);
|
||||
}
|
||||
|
||||
if let Some(handler) = ipc_handler {
|
||||
webview_builder = webview_builder.with_ipc_handler(create_ipc_handler(
|
||||
context,
|
||||
|
||||
@@ -224,6 +224,9 @@ pub struct PendingWindow<T: UserEvent, R: Runtime<T>> {
|
||||
|
||||
pub uri_scheme_protocols: HashMap<String, Box<UriSchemeProtocol>>,
|
||||
|
||||
// Whether custom protocols on windows should use http://<scheme>.localhost/ instead of https://<scheme>.localhost/
|
||||
pub http_scheme: bool,
|
||||
|
||||
/// How to handle IPC calls on the webview window.
|
||||
pub ipc_handler: Option<WebviewIpcHandler<T, R>>,
|
||||
|
||||
@@ -281,6 +284,7 @@ impl<T: UserEvent, R: Runtime<T>> PendingWindow<T, R> {
|
||||
navigation_handler: Default::default(),
|
||||
web_resource_request_handler: Default::default(),
|
||||
url: "tauri://localhost".to_string(),
|
||||
http_scheme: false,
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -312,6 +316,7 @@ impl<T: UserEvent, R: Runtime<T>> PendingWindow<T, R> {
|
||||
navigation_handler: Default::default(),
|
||||
web_resource_request_handler: Default::default(),
|
||||
url: "tauri://localhost".to_string(),
|
||||
http_scheme: false,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1326,6 +1326,11 @@ pub struct SecurityConfig {
|
||||
/// vulnerable to dangerous Tauri command related attacks otherwise.
|
||||
#[serde(default, alias = "dangerous-remote-domain-ipc-access")]
|
||||
pub dangerous_remote_domain_ipc_access: Vec<RemoteDomainAccessScope>,
|
||||
/// Sets whether the custom protocols should use `http://<scheme>.localhost` instead of the default `https://<scheme>.localhost` on Windows.
|
||||
///
|
||||
/// **WARNING:** Using a `http` scheme will allow mixed content when trying to fetch `http` endpoints and is therefore less secure but will match the behavior of the `<scheme>://localhost` protocols used on macOS and Linux.
|
||||
#[serde(default, alias = "dangerous-use-http-scheme")]
|
||||
pub dangerous_use_http_scheme: bool,
|
||||
}
|
||||
|
||||
/// Defines an allowlist type.
|
||||
@@ -3736,6 +3741,7 @@ mod build {
|
||||
let dev_csp = opt_lit(self.dev_csp.as_ref());
|
||||
let freeze_prototype = self.freeze_prototype;
|
||||
let dangerous_disable_asset_csp_modification = &self.dangerous_disable_asset_csp_modification;
|
||||
let dangerous_use_http_scheme = &self.dangerous_use_http_scheme;
|
||||
let dangerous_remote_domain_ipc_access =
|
||||
vec_lit(&self.dangerous_remote_domain_ipc_access, identity);
|
||||
|
||||
@@ -3746,7 +3752,8 @@ mod build {
|
||||
dev_csp,
|
||||
freeze_prototype,
|
||||
dangerous_disable_asset_csp_modification,
|
||||
dangerous_remote_domain_ipc_access
|
||||
dangerous_remote_domain_ipc_access,
|
||||
dangerous_use_http_scheme
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -4013,6 +4020,7 @@ mod test {
|
||||
freeze_prototype: false,
|
||||
dangerous_disable_asset_csp_modification: DisabledCspModificationKind::Flag(false),
|
||||
dangerous_remote_domain_ipc_access: Vec::new(),
|
||||
dangerous_use_http_scheme: false,
|
||||
},
|
||||
allowlist: AllowlistConfig::default(),
|
||||
system_tray: None,
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -13,6 +13,16 @@
|
||||
})
|
||||
}
|
||||
|
||||
const osName = __TEMPLATE_os_name__
|
||||
const protocolScheme = __TEMPLATE_protocol_scheme__
|
||||
|
||||
window.__TAURI__.convertFileSrc = function convertFileSrc(filePath, protocol = 'asset') {
|
||||
const path = encodeURIComponent(filePath)
|
||||
return osName === 'windows'
|
||||
? `${protocolScheme}://${protocol}.localhost/${path}`
|
||||
: `${protocol}://localhost/${path}`
|
||||
}
|
||||
|
||||
window.__TAURI__.transformCallback = function transformCallback(
|
||||
callback,
|
||||
once
|
||||
|
||||
@@ -1573,16 +1573,17 @@ impl<R: Runtime> Builder<R> {
|
||||
(self.invoke_responder, self.invoke_initialization_script),
|
||||
);
|
||||
|
||||
let http_scheme = manager.config().tauri.security.dangerous_use_http_scheme;
|
||||
|
||||
// set up all the windows defined in the config
|
||||
for config in manager.config().tauri.windows.clone() {
|
||||
let label = config.label.clone();
|
||||
let webview_attributes = WebviewAttributes::from(&config);
|
||||
|
||||
self.pending_windows.push(PendingWindow::with_config(
|
||||
config,
|
||||
webview_attributes,
|
||||
label,
|
||||
)?);
|
||||
let mut pending = PendingWindow::with_config(config, webview_attributes, label)?;
|
||||
pending.http_scheme = http_scheme;
|
||||
|
||||
self.pending_windows.push(pending);
|
||||
}
|
||||
|
||||
#[cfg(any(windows, target_os = "linux"))]
|
||||
|
||||
@@ -142,7 +142,10 @@ fn set_csp<R: Runtime>(
|
||||
let default_src = csp
|
||||
.entry("default-src".into())
|
||||
.or_insert_with(Default::default);
|
||||
default_src.push(crate::pattern::format_real_schema(schema));
|
||||
default_src.push(crate::pattern::format_real_schema(
|
||||
schema,
|
||||
manager.config().tauri.security.dangerous_use_http_scheme,
|
||||
));
|
||||
}
|
||||
|
||||
Csp::DirectiveMap(csp).to_string()
|
||||
@@ -388,7 +391,14 @@ impl<R: Runtime> WindowManager<R> {
|
||||
match self.base_path() {
|
||||
AppUrl::Url(WindowUrl::External(url)) => Cow::Borrowed(url),
|
||||
#[cfg(windows)]
|
||||
_ => Cow::Owned(Url::parse("https://tauri.localhost").unwrap()),
|
||||
_ => {
|
||||
let scheme = if self.inner.config.tauri.security.dangerous_use_http_scheme {
|
||||
"http"
|
||||
} else {
|
||||
"https"
|
||||
};
|
||||
Cow::Owned(Url::parse(&format!("{scheme}://tauri.localhost")).unwrap())
|
||||
}
|
||||
#[cfg(not(windows))]
|
||||
_ => Cow::Owned(Url::parse("tauri://localhost").unwrap()),
|
||||
}
|
||||
@@ -429,17 +439,19 @@ impl<R: Runtime> WindowManager<R> {
|
||||
}
|
||||
.render_default(&Default::default())?;
|
||||
|
||||
let mut webview_attributes = pending.webview_attributes;
|
||||
|
||||
let ipc_init = IpcJavascript {
|
||||
isolation_origin: &match self.pattern() {
|
||||
#[cfg(feature = "isolation")]
|
||||
Pattern::Isolation { schema, .. } => crate::pattern::format_real_schema(schema),
|
||||
Pattern::Isolation { schema, .. } => {
|
||||
crate::pattern::format_real_schema(schema, pending.http_scheme)
|
||||
}
|
||||
_ => "".to_string(),
|
||||
},
|
||||
}
|
||||
.render_default(&Default::default())?;
|
||||
|
||||
let mut webview_attributes = pending.webview_attributes;
|
||||
|
||||
let mut window_labels = window_labels.to_vec();
|
||||
let l = label.to_string();
|
||||
if !window_labels.contains(&l) {
|
||||
@@ -466,7 +478,7 @@ impl<R: Runtime> WindowManager<R> {
|
||||
if let Pattern::Isolation { schema, .. } = self.pattern() {
|
||||
webview_attributes = webview_attributes.initialization_script(
|
||||
&IsolationJavascript {
|
||||
isolation_src: &crate::pattern::format_real_schema(schema),
|
||||
isolation_src: &crate::pattern::format_real_schema(schema, pending.http_scheme),
|
||||
style: tauri_utils::pattern::isolation::IFRAME_STYLE,
|
||||
}
|
||||
.render_default(&Default::default())?
|
||||
@@ -491,7 +503,8 @@ impl<R: Runtime> WindowManager<R> {
|
||||
let window_origin = if window_url.scheme() == "data" {
|
||||
"null".into()
|
||||
} else if cfg!(windows) && window_url.scheme() != "http" && window_url.scheme() != "https" {
|
||||
format!("https://{}.localhost", window_url.scheme())
|
||||
let scheme = if pending.http_scheme { "http" } else { "https" };
|
||||
format!("{scheme}://{}.localhost", window_url.scheme())
|
||||
} else {
|
||||
format!(
|
||||
"{}://{}{}",
|
||||
@@ -782,6 +795,13 @@ impl<R: Runtime> WindowManager<R> {
|
||||
hotkeys: &'a str,
|
||||
}
|
||||
|
||||
#[derive(Template)]
|
||||
#[default_template("../scripts/core.js")]
|
||||
struct CoreJavascript<'a> {
|
||||
os_name: &'a str,
|
||||
protocol_scheme: &'a str,
|
||||
}
|
||||
|
||||
let bundle_script = if with_global_tauri {
|
||||
include_str!("../scripts/bundle.global.js")
|
||||
} else {
|
||||
@@ -813,7 +833,16 @@ impl<R: Runtime> WindowManager<R> {
|
||||
"window['_' + window.__TAURI__.transformCallback(cb) ]".into()
|
||||
)
|
||||
),
|
||||
core_script: include_str!("../scripts/core.js"),
|
||||
core_script: &CoreJavascript {
|
||||
os_name: std::env::consts::OS,
|
||||
protocol_scheme: if self.inner.config.tauri.security.dangerous_use_http_scheme {
|
||||
"http"
|
||||
} else {
|
||||
"https"
|
||||
},
|
||||
}
|
||||
.render_default(&Default::default())?
|
||||
.into_string(),
|
||||
event_initialization_script: &self.event_initialization_script(),
|
||||
plugin_initialization_script,
|
||||
freeze_prototype,
|
||||
|
||||
@@ -108,9 +108,10 @@ pub(crate) struct PatternJavascript {
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub(crate) fn format_real_schema(schema: &str) -> String {
|
||||
pub(crate) fn format_real_schema(schema: &str, _http: bool) -> String {
|
||||
if cfg!(windows) {
|
||||
format!("https://{schema}.{ISOLATION_IFRAME_SRC_DOMAIN}")
|
||||
let http = if _http { "http" } else { "https" };
|
||||
format!("{http}://{schema}.{ISOLATION_IFRAME_SRC_DOMAIN}")
|
||||
} else {
|
||||
format!("{schema}://{ISOLATION_IFRAME_SRC_DOMAIN}")
|
||||
}
|
||||
|
||||
@@ -329,6 +329,12 @@ impl<'a, R: Runtime> WindowBuilder<'a, R> {
|
||||
)?;
|
||||
pending.navigation_handler = self.navigation_handler.take();
|
||||
pending.web_resource_request_handler = self.web_resource_request_handler.take();
|
||||
pending.http_scheme = self
|
||||
.manager
|
||||
.config()
|
||||
.tauri
|
||||
.security
|
||||
.dangerous_use_http_scheme;
|
||||
|
||||
let labels = self.manager.labels().into_iter().collect::<Vec<_>>();
|
||||
let pending = self
|
||||
|
||||
@@ -17,6 +17,9 @@ declare global {
|
||||
ipc: {
|
||||
postMessage: (args: string) => void
|
||||
}
|
||||
__TAURI__: {
|
||||
convertFileSrc: (src: string, protocol: string) => string
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -127,10 +130,7 @@ async function invoke<T>(cmd: string, args: InvokeArgs = {}): Promise<T> {
|
||||
* @since 1.0.0
|
||||
*/
|
||||
function convertFileSrc(filePath: string, protocol = 'asset'): string {
|
||||
const path = encodeURIComponent(filePath)
|
||||
return navigator.userAgent.includes('Windows')
|
||||
? `https://${protocol}.localhost/${path}`
|
||||
: `${protocol}://localhost/${path}`
|
||||
return window.__TAURI__.convertFileSrc(filePath, protocol)
|
||||
}
|
||||
|
||||
export type { InvokeArgs }
|
||||
|
||||
@@ -167,6 +167,7 @@
|
||||
"security": {
|
||||
"dangerousDisableAssetCspModification": false,
|
||||
"dangerousRemoteDomainIpcAccess": [],
|
||||
"dangerousUseHttpScheme": false,
|
||||
"freezePrototype": false
|
||||
},
|
||||
"updater": {
|
||||
@@ -423,6 +424,7 @@
|
||||
"default": {
|
||||
"dangerousDisableAssetCspModification": false,
|
||||
"dangerousRemoteDomainIpcAccess": [],
|
||||
"dangerousUseHttpScheme": false,
|
||||
"freezePrototype": false
|
||||
},
|
||||
"allOf": [
|
||||
@@ -2740,6 +2742,11 @@
|
||||
"items": {
|
||||
"$ref": "#/definitions/RemoteDomainAccessScope"
|
||||
}
|
||||
},
|
||||
"dangerousUseHttpScheme": {
|
||||
"description": "Sets whether the custom protocols should use `http://<scheme>.localhost` instead of the default `https://<scheme>.localhost` on Windows.\n\n**WARNING:** Using a `http` scheme will allow mixed content when trying to fetch `http` endpoints and is therefore less secure but will match the behavior of the `<scheme>://localhost` protocols used on macOS and Linux.",
|
||||
"default": false,
|
||||
"type": "boolean"
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
|
||||
Reference in New Issue
Block a user