feat(cli): improve bundle identifier validation, closes #4589 (#4596)

This commit is contained in:
Lucas Fernandes Nogueira 2022-07-05 19:57:31 -03:00 committed by GitHub
parent 92aca55a6f
commit 8e3e7fc646
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 122 additions and 18 deletions

View File

@ -0,0 +1,6 @@
---
"cli.rs": patch
"cli.js": patch
---
Improved bundle identifier validation showing the exact source of the configuration value.

View File

@ -0,0 +1,5 @@
---
"tauri-utils": patch
---
Added `config::parse::read_platform` and `config::parse::get_platform_config_filename`.

View File

@ -82,20 +82,34 @@ pub enum ConfigError {
/// [JSON Merge Patch (RFC 7396)]: https://datatracker.ietf.org/doc/html/rfc7396.
pub fn read_from(root_dir: PathBuf) -> Result<Value, ConfigError> {
let mut config: Value = parse_value(root_dir.join("tauri.conf.json"))?;
if let Some(platform_config) = read_platform(root_dir)? {
merge(&mut config, &platform_config);
}
Ok(config)
}
let platform_config_filename = if cfg!(target_os = "macos") {
/// Gets the platform configuration file name.
pub fn get_platform_config_filename() -> &'static str {
if cfg!(target_os = "macos") {
"tauri.macos.conf.json"
} else if cfg!(windows) {
"tauri.windows.conf.json"
} else {
"tauri.linux.conf.json"
};
let platform_config_path = root_dir.join(platform_config_filename);
}
}
/// Reads the platform-specific configuration file from the given root directory if it exists.
///
/// Check [`read_from`] for more information.
pub fn read_platform(root_dir: PathBuf) -> Result<Option<Value>, ConfigError> {
let platform_config_path = root_dir.join(get_platform_config_filename());
if does_supported_extension_exist(&platform_config_path) {
let platform_config: Value = parse_value(platform_config_path)?;
merge(&mut config, &platform_config);
Ok(Some(platform_config))
} else {
Ok(None)
}
Ok(config)
}
/// Check if a supported config file exists at path.

View File

@ -6,7 +6,7 @@ use crate::{
helpers::{
app_paths::{app_dir, tauri_dir},
command_env,
config::{get as get_config, AppUrl, WindowUrl},
config::{get as get_config, AppUrl, WindowUrl, MERGE_CONFIG_EXTENSION_NAME},
updater_signature::sign_file_from_env_variables,
},
interface::{AppInterface, AppSettings, Interface},
@ -54,15 +54,22 @@ pub struct Options {
}
pub fn command(mut options: Options) -> Result<()> {
options.config = if let Some(config) = &options.config {
Some(if config.starts_with('{') {
config.to_string()
let (merge_config, merge_config_path) = if let Some(config) = &options.config {
if config.starts_with('{') {
(Some(config.to_string()), None)
} else {
std::fs::read_to_string(&config).with_context(|| "failed to read custom configuration")?
})
(
Some(
std::fs::read_to_string(&config)
.with_context(|| "failed to read custom configuration")?,
),
Some(config.clone()),
)
}
} else {
None
(None, None)
};
options.config = merge_config;
let tauri_path = tauri_dir();
set_current_dir(&tauri_path).with_context(|| "failed to change current working directory")?;
@ -72,8 +79,19 @@ pub fn command(mut options: Options) -> Result<()> {
let config_guard = config.lock().unwrap();
let config_ = config_guard.as_ref().unwrap();
let bundle_identifier_source = match config_.find_bundle_identifier_overwriter() {
Some(source) if source == MERGE_CONFIG_EXTENSION_NAME => {
merge_config_path.unwrap_or_else(|| source.into())
}
Some(source) => source.into(),
None => "tauri.conf.json".into(),
};
if config_.tauri.bundle.identifier == "com.tauri.dev" {
error!("You must change the bundle identifier in `tauri.conf.json > tauri > bundle > identifier`. The default value `com.tauri.dev` is not allowed as it must be unique across applications.");
error!(
"You must change the bundle identifier in `{} > tauri > bundle > identifier`. The default value `com.tauri.dev` is not allowed as it must be unique across applications.",
bundle_identifier_source
);
std::process::exit(1);
}
@ -84,7 +102,11 @@ pub fn command(mut options: Options) -> Result<()> {
.chars()
.any(|ch| !(ch.is_alphanumeric() || ch == '-' || ch == '.'))
{
error!("You must change the bundle identifier in `tauri.conf.json > tauri > bundle > identifier`. The bundle identifier string must contain only alphanumeric characters (AZ, az, and 09), hyphens (-), and periods (.).");
error!(
"The bundle identifier \"{}\" set in `{} > tauri > bundle > identifier`. The bundle identifier string must contain only alphanumeric characters (AZ, az, and 09), hyphens (-), and periods (.).",
config_.tauri.bundle.identifier,
bundle_identifier_source
);
std::process::exit(1);
}

View File

@ -10,12 +10,54 @@ use serde_json::Value as JsonValue;
pub use tauri_utils::config::*;
use std::{
collections::HashMap,
env::set_var,
process::exit,
sync::{Arc, Mutex},
};
pub type ConfigHandle = Arc<Mutex<Option<Config>>>;
pub const MERGE_CONFIG_EXTENSION_NAME: &str = "--config";
pub struct ConfigMetadata {
/// The actual configuration, merged with any extension.
inner: Config,
/// The config extensions (platform-specific config files or the config CLI argument).
/// Maps the extension name to its value.
extensions: HashMap<&'static str, JsonValue>,
}
impl std::ops::Deref for ConfigMetadata {
type Target = Config;
#[inline(always)]
fn deref(&self) -> &Config {
&self.inner
}
}
impl ConfigMetadata {
/// Checks which config is overwriting the bundle identifier.
pub fn find_bundle_identifier_overwriter(&self) -> Option<&'static str> {
for (ext, config) in &self.extensions {
if let Some(identifier) = config
.as_object()
.and_then(|config| config.get("tauri"))
.and_then(|tauri_config| tauri_config.as_object())
.and_then(|tauri_config| tauri_config.get("bundle"))
.and_then(|bundle_config| bundle_config.as_object())
.and_then(|bundle_config| bundle_config.get("identifier"))
.and_then(|id| id.as_str())
{
if identifier == self.inner.tauri.bundle.identifier {
return Some(ext);
}
}
}
None
}
}
pub type ConfigHandle = Arc<Mutex<Option<ConfigMetadata>>>;
pub fn wix_settings(config: WixConfig) -> tauri_bundler::WixSettings {
tauri_bundler::WixSettings {
@ -63,13 +105,24 @@ fn get_internal(merge_config: Option<&str>, reload: bool) -> crate::Result<Confi
return Ok(config_handle().clone());
}
let mut config = tauri_utils::config::parse::read_from(super::app_paths::tauri_dir())?;
let tauri_dir = super::app_paths::tauri_dir();
let mut config = tauri_utils::config::parse::parse_value(tauri_dir.join("tauri.conf.json"))?;
let mut extensions = HashMap::new();
if let Some(platform_config) = tauri_utils::config::parse::read_platform(tauri_dir)? {
merge(&mut config, &platform_config);
extensions.insert(
tauri_utils::config::parse::get_platform_config_filename(),
platform_config,
);
}
if let Some(merge_config) = merge_config {
let merge_config: JsonValue =
serde_json::from_str(merge_config).with_context(|| "failed to parse config to merge")?;
merge(&mut config, &merge_config);
}
extensions.insert(MERGE_CONFIG_EXTENSION_NAME, merge_config);
};
let schema: JsonValue = serde_json::from_str(include_str!("../../schema.json"))?;
let mut scope = valico::json_schema::Scope::new();
@ -93,7 +146,11 @@ fn get_internal(merge_config: Option<&str>, reload: bool) -> crate::Result<Confi
let config: Config = serde_json::from_value(config)?;
set_var("TAURI_CONFIG", serde_json::to_string(&config)?);
*config_handle().lock().unwrap() = Some(config);
*config_handle().lock().unwrap() = Some(ConfigMetadata {
inner: config,
extensions,
});
Ok(config_handle().clone())
}