feat(core): Allow http origin on Windows, fixes: #3007 (#7645)

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:
Fabian-Lars
2023-09-26 19:40:38 +02:00
committed by GitHub
parent e8ff6b153e
commit 9aa34ada57
13 changed files with 112 additions and 25 deletions

View 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.

View File

@@ -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

View File

@@ -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,

View File

@@ -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,
})
}
}

View File

@@ -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

View File

@@ -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

View File

@@ -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"))]

View File

@@ -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,

View File

@@ -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}")
}

View File

@@ -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

View File

@@ -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 }

View File

@@ -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