Compare commits

..

1 Commits

Author SHA1 Message Date
FabianLars
af64de041b feat: add Referer to HeaderConfig 2025-11-05 13:43:00 +01:00
9 changed files with 103 additions and 93 deletions

27
Cargo.lock generated
View File

@@ -1319,7 +1319,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "117725a109d387c937a1533ce01b450cbde6b88abceea8473c4d7a85853cda3c"
dependencies = [
"lazy_static",
"windows-sys 0.59.0",
"windows-sys 0.48.0",
]
[[package]]
@@ -1641,12 +1641,6 @@ dependencies = [
"syn 2.0.95",
]
[[package]]
name = "ct-codecs"
version = "1.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9b10589d1a5e400d61f9f38f12f884cfd080ff345de8f17efda36fe0e4a02aa8"
[[package]]
name = "ctor"
version = "0.2.9"
@@ -2866,11 +2860,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "26145e563e54f2cadc477553f1ec5ee650b00862f0a58bcd12cbdc5f0ea2d2f4"
dependencies = [
"cfg-if",
"js-sys",
"libc",
"r-efi",
"wasi 0.14.2+wasi-0.2.4",
"wasm-bindgen",
]
[[package]]
@@ -4319,7 +4311,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fc2f4eb4bc735547cfed7c0a4922cbd04a4655978c09b54f1f7b228750664c34"
dependencies = [
"cfg-if",
"windows-targets 0.52.6",
"windows-targets 0.48.5",
]
[[package]]
@@ -4600,12 +4592,11 @@ checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a"
[[package]]
name = "minisign"
version = "0.8.0"
version = "0.7.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e6bf96cef396a17a96f7600281aa4da9229860b7a082601b1f6db6eaa5f99ee5"
checksum = "b23ef13ff1d745b1e52397daaa247e333c607f3cff96d4df2b798dc252db974b"
dependencies = [
"ct-codecs",
"getrandom 0.3.3",
"getrandom 0.2.15",
"rpassword",
"scrypt",
]
@@ -6985,13 +6976,13 @@ checksum = "6c20b6793b5c2fa6553b250154b78d6d0db37e72700ae35fad9387a46f487c97"
[[package]]
name = "rpassword"
version = "7.4.0"
version = "7.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "66d4c8b64f049c6721ec8ccec37ddfc3d641c4a7fca57e8f2a89de509c73df39"
checksum = "80472be3c897911d0137b2d2b9055faf6eeac5b14e324073d83bc17b191d7e3f"
dependencies = [
"libc",
"rtoolbox",
"windows-sys 0.59.0",
"windows-sys 0.48.0",
]
[[package]]
@@ -10324,7 +10315,7 @@ version = "0.1.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb"
dependencies = [
"windows-sys 0.59.0",
"windows-sys 0.48.0",
]
[[package]]

View File

@@ -70,7 +70,7 @@ jsonschema = "0.33"
handlebars = "6"
include_dir = "0.7"
dirs = "6"
minisign = "0.8"
minisign = "=0.7.3"
base64 = "0.22"
ureq = { version = "3", default-features = false, features = ["gzip"] }
os_info = "3"

View File

@@ -1767,6 +1767,17 @@
}
]
},
"Referer": {
"description": "TODO: docs",
"anyOf": [
{
"$ref": "#/definitions/HeaderSource"
},
{
"type": "null"
}
]
},
"Tauri-Custom-Header": {
"description": "A custom header field Tauri-Custom-Header, don't use it.\n Remember to set Access-Control-Expose-Headers accordingly\n\n **NOT INTENDED FOR PRODUCTION USE**",
"anyOf": [

View File

@@ -203,7 +203,7 @@ where
mod tests {
const PRIVATE_KEY: &str = "dW50cnVzdGVkIGNvbW1lbnQ6IHJzaWduIGVuY3J5cHRlZCBzZWNyZXQga2V5ClJXUlRZMEl5dkpDN09RZm5GeVAzc2RuYlNzWVVJelJRQnNIV2JUcGVXZUplWXZXYXpqUUFBQkFBQUFBQUFBQUFBQUlBQUFBQTZrN2RnWGh5dURxSzZiL1ZQSDdNcktiaHRxczQwMXdQelRHbjRNcGVlY1BLMTBxR2dpa3I3dDE1UTVDRDE4MXR4WlQwa1BQaXdxKy9UU2J2QmVSNXhOQWFDeG1GSVllbUNpTGJQRkhhTnROR3I5RmdUZi90OGtvaGhJS1ZTcjdZU0NyYzhQWlQ5cGM9Cg==";
// minisign >=0.7.4,<0.8.0 couldn't handle empty passwords.
// we use minisign=0.7.3 to prevent a breaking change
#[test]
fn empty_password_is_valid() {
let path = std::env::temp_dir().join("minisign-password-text.txt");

View File

@@ -65,23 +65,28 @@ impl FromStr for ConfigValue {
let path = PathBuf::from(config);
let raw =
read_to_string(&path).fs_context("failed to read configuration file", path.clone())?;
// treat all other extensions as json
// from tauri-utils/src/config/parse.rs:
// we also want to support **valid** json5 in the .json extension
// if the json5 is not valid the serde_json error for regular json will be returned.
match path.extension().and_then(|ext| ext.to_str()) {
Some("toml") => Ok(Self(::toml::from_str(&raw).with_context(|| {
format!("failed to parse config at {} as TOML", path.display())
})?)),
Some("json5") => Ok(Self(::json5::from_str(&raw).with_context(|| {
format!("failed to parse config at {} as JSON5", path.display())
})?)),
_ => Ok(Self(match ::json5::from_str(&raw) {
Ok(json5) => json5,
Err(_) => serde_json::from_str(&raw)
.with_context(|| format!("failed to parse config at {} as JSON", path.display()))?,
})),
match path.extension() {
Some(ext) if ext == "toml" => {
Ok(Self(::toml::from_str(&raw).with_context(|| {
format!("failed to parse config at {} as TOML", path.display())
})?))
}
Some(ext) if ext == "json5" => {
Ok(Self(::json5::from_str(&raw).with_context(|| {
format!("failed to parse config at {} as JSON5", path.display())
})?))
}
// treat all other extensions as json
_ => Ok(Self(
// from tauri-utils/src/config/parse.rs:
// we also want to support **valid** json5 in the .json extension
// if the json5 is not valid the serde_json error for regular json will be returned.
match ::json5::from_str(&raw) {
Ok(json5) => json5,
Err(_) => serde_json::from_str(&raw)
.with_context(|| format!("failed to parse config at {} as JSON", path.display()))?,
},
)),
}
}
}
@@ -173,13 +178,6 @@ fn format_error<I: CommandFactory>(err: clap::Error) -> clap::Error {
err.format(&mut app)
}
fn get_verbosity(cli_verbose: u8) -> u8 {
std::env::var("TAURI_CLI_VERBOSITY")
.ok()
.and_then(|v| v.parse().ok())
.unwrap_or(cli_verbose)
}
/// Run the Tauri CLI with the passed arguments, exiting if an error occurs.
///
/// The passed arguments should have the binary argument(s) stripped out before being passed.
@@ -224,17 +222,23 @@ where
Err(e) => e.exit(),
};
let verbosity_number = get_verbosity(cli.verbose);
let verbosity_number = std::env::var("TAURI_CLI_VERBOSITY")
.ok()
.and_then(|v| v.parse().ok())
.unwrap_or(cli.verbose);
// set the verbosity level so subsequent CLI calls (xcode-script, android-studio-script) refer to it
std::env::set_var("TAURI_CLI_VERBOSITY", verbosity_number.to_string());
let mut builder = Builder::from_default_env();
if let Err(err) = builder
let init_res = builder
.format_indent(Some(12))
.filter(None, verbosity_level(verbosity_number).to_level_filter())
// golbin spams an insane amount of really technical logs on the debug level so we're reducing one level
.filter(
Some("goblin"),
verbosity_level(verbosity_number.saturating_sub(1)).to_level_filter(),
)
// handlebars is not that spammy but its debug logs are typically far from being helpful
.filter(
Some("handlebars"),
verbosity_level(verbosity_number.saturating_sub(1)).to_level_filter(),
@@ -246,6 +250,7 @@ where
is_command_output = action == "stdout" || action == "stderr";
if !is_command_output {
let style = Style::new().fg_color(Some(AnsiColor::Green.into())).bold();
write!(f, "{style}{action:>12}{style:#} ")?;
}
} else {
@@ -259,13 +264,15 @@ where
if !is_command_output && log::log_enabled!(Level::Debug) {
let style = Style::new().fg_color(Some(AnsiColor::Black.into()));
write!(f, "[{style}{}{style:#}] ", record.target())?;
}
writeln!(f, "{}", record.args())
})
.try_init()
{
.try_init();
if let Err(err) = init_res {
eprintln!("Failed to attach logger: {err}");
}
@@ -298,7 +305,7 @@ fn verbosity_level(num: u8) -> Level {
match num {
0 => Level::Info,
1 => Level::Debug,
_ => Level::Trace,
2.. => Level::Trace,
}
}
@@ -314,6 +321,8 @@ fn prettyprint_level(lvl: Level) -> &'static str {
}
pub trait CommandExt {
// The `pipe` function sets the stdout and stderr to properly
// show the command output in the Node.js wrapper.
fn piped(&mut self) -> std::io::Result<ExitStatus>;
fn output_ok(&mut self) -> crate::Result<Output>;
}
@@ -323,15 +332,9 @@ impl CommandExt for Command {
self.stdin(os_pipe::dup_stdin()?);
self.stdout(os_pipe::dup_stdout()?);
self.stderr(os_pipe::dup_stderr()?);
let program = self.get_program().to_string_lossy().into_owned();
let args = self
.get_args()
.map(|a| a.to_string_lossy())
.collect::<Vec<_>>()
.join(" ");
log::debug!(action = "Running"; "Command `{} {}`", program, self.get_args().map(|arg| arg.to_string_lossy()).fold(String::new(), |acc, arg| format!("{acc} {arg}")));
log::debug!(action = "Running"; "Command `{program} {args}`");
self.status()
}
@@ -339,9 +342,8 @@ impl CommandExt for Command {
let program = self.get_program().to_string_lossy().into_owned();
let args = self
.get_args()
.map(|a| a.to_string_lossy())
.collect::<Vec<_>>()
.join(" ");
.map(|arg| arg.to_string_lossy())
.fold(String::new(), |acc, arg| format!("{acc} {arg}"));
let cmdline = format!("{program} {args}");
log::debug!(action = "Running"; "Command `{cmdline}`");
@@ -357,17 +359,16 @@ impl CommandExt for Command {
let stdout_lines_ = stdout_lines.clone();
std::thread::spawn(move || {
let mut line = String::new();
if let Ok(mut lines) = stdout_lines_.lock() {
loop {
line.clear();
match stdout.read_line(&mut line) {
Ok(0) => break,
Ok(_) => {
log::debug!(action = "stdout"; "{}", line.trim_end());
lines.extend(line.as_bytes());
}
Err(_) => (),
let mut lines = stdout_lines_.lock().unwrap();
loop {
line.clear();
match stdout.read_line(&mut line) {
Ok(0) => break,
Ok(_) => {
log::debug!(action = "stdout"; "{}", line.trim_end());
lines.extend(line.as_bytes().to_vec());
}
Err(_) => (),
}
}
});
@@ -377,17 +378,16 @@ impl CommandExt for Command {
let stderr_lines_ = stderr_lines.clone();
std::thread::spawn(move || {
let mut line = String::new();
if let Ok(mut lines) = stderr_lines_.lock() {
loop {
line.clear();
match stderr.read_line(&mut line) {
Ok(0) => break,
Ok(_) => {
log::debug!(action = "stderr"; "{}", line.trim_end());
lines.extend(line.as_bytes());
}
Err(_) => (),
let mut lines = stderr_lines_.lock().unwrap();
loop {
line.clear();
match stderr.read_line(&mut line) {
Ok(0) => break,
Ok(_) => {
log::debug!(action = "stderr"; "{}", line.trim_end());
lines.extend(line.as_bytes().to_vec());
}
Err(_) => (),
}
}
});
@@ -423,10 +423,4 @@ mod tests {
fn verify_cli() {
Cli::command().debug_assert();
}
#[test]
fn help_output_includes_build() {
let help = Cli::command().render_help().to_string();
assert!(help.contains("Build"));
}
}

View File

@@ -1767,6 +1767,17 @@
}
]
},
"Referer": {
"description": "TODO: docs",
"anyOf": [
{
"$ref": "#/definitions/HeaderSource"
},
{
"type": "null"
}
]
},
"Tauri-Custom-Header": {
"description": "A custom header field Tauri-Custom-Header, don't use it.\n Remember to set Access-Control-Expose-Headers accordingly\n\n **NOT INTENDED FOR PRODUCTION USE**",
"anyOf": [

View File

@@ -2390,6 +2390,11 @@ impl HeaderAddition for Builder {
self = self.header("X-Content-Type-Options", value.to_string());
};
// Add the header X-Content-Type-Options, if we find a value for it
if let Some(value) = &headers.referer {
self = self.header("Referer", value.to_string());
};
// Add the header Tauri-Custom-Header, if we find a value for it
if let Some(value) = &headers.tauri_custom_header {
// Keep in mind to correctly set the Access-Control-Expose-Headers
@@ -2543,6 +2548,9 @@ pub struct HeaderConfig {
/// See <https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Content-Type-Options>
#[serde(rename = "X-Content-Type-Options")]
pub x_content_type_options: Option<HeaderSource>,
/// TODO: docs
#[serde(rename = "Referer")]
pub referer: Option<HeaderSource>,
/// A custom header field Tauri-Custom-Header, don't use it.
/// Remember to set Access-Control-Expose-Headers accordingly
///
@@ -2567,6 +2575,7 @@ impl HeaderConfig {
service_worker_allowed: None,
timing_allow_origin: None,
x_content_type_options: None,
referer: None,
tauri_custom_header: None,
}
}
@@ -3920,6 +3929,7 @@ mod build {
let service_worker_allowed = opt_lit(self.service_worker_allowed.as_ref());
let timing_allow_origin = opt_lit(self.timing_allow_origin.as_ref());
let x_content_type_options = opt_lit(self.x_content_type_options.as_ref());
let referer = opt_lit(self.referer.as_ref());
let tauri_custom_header = opt_lit(self.tauri_custom_header.as_ref());
literal_struct!(
@@ -3937,6 +3947,7 @@ mod build {
service_worker_allowed,
timing_allow_origin,
x_content_type_options,
referer,
tauri_custom_header
);
}

View File

@@ -1037,7 +1037,6 @@ macro_rules! shared_app_impl {
for (_, webview) in self.manager.webviews() {
webview.resources_table().clear();
}
unsafe { self.manager.state.clear() };
}
/// Gets the invoke key that must be referenced when using [`crate::webview::InvokeRequest`].

View File

@@ -149,13 +149,6 @@ impl StateManager {
Some(*value)
}
/// SAFETY: This will cause all references obtained through [Self::try_get] to dangle.
/// This must only be called on app exit (in cleanup_before_exit).
pub(crate) unsafe fn clear(&self) {
let mut map = self.map.lock().unwrap();
map.clear();
}
/// Gets the state associated with the specified type.
pub fn get<T: Send + Sync + 'static>(&self) -> State<'_, T> {
self