Skip to content

Commit

Permalink
refactor: embed resources starting from root, disable traversal
Browse files Browse the repository at this point in the history
  • Loading branch information
amr-crabnebula committed Sep 12, 2023
1 parent 5025177 commit 967bf35
Show file tree
Hide file tree
Showing 8 changed files with 103 additions and 109 deletions.
2 changes: 1 addition & 1 deletion crates/config/schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -175,7 +175,7 @@
}
},
"resources": {
"description": "The app's resources to package. This a list of either a path to a resource (with optional glob pattern) or an object of `src` and `target` paths.\n\n## Format-specific:\n\n- **[PackageFormat::Nsis] / [PackageFormat::Wix]**: The resources are placed next to the executable in the root of the packager. - **[PackageFormat::Deb]**: The resources are placed in `usr/lib` of the package.",
"description": "The app's resources to package. This a list of either a glob pattern, path to a file, path to a directory or an object of `src` and `target` paths. In the case of using an object, the `src` could be either a glob pattern, path to a file, path to a directory, and the `target` is a path inside the final resources folder in the installed package.\n\n## Format-specific:\n\n- **[PackageFormat::Nsis] / [PackageFormat::Wix]**: The resources are placed next to the executable in the root of the packager. - **[PackageFormat::Deb]**: The resources are placed in `usr/lib` of the package.",
"type": [
"array",
"null"
Expand Down
8 changes: 5 additions & 3 deletions crates/config/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -454,7 +454,7 @@ pub enum Resource {
/// Supports glob patterns
Single(String),
Mapped {
src: PathBuf,
src: String,
target: PathBuf,
},
}
Expand Down Expand Up @@ -548,8 +548,10 @@ pub struct Config {
/// the file associations
#[serde(alias = "file-associations", alias = "file_associations")]
pub file_associations: Option<Vec<FileAssociation>>,
/// The app's resources to package. This a list of either a path to a resource (with optional glob pattern)
/// or an object of `src` and `target` paths.
/// The app's resources to package. This a list of either a glob pattern, path to a file, path to a directory
/// or an object of `src` and `target` paths. In the case of using an object,
/// the `src` could be either a glob pattern, path to a file, path to a directory,
/// and the `target` is a path inside the final resources folder in the installed package.
///
/// ## Format-specific:
///
Expand Down
2 changes: 1 addition & 1 deletion crates/packager/schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -175,7 +175,7 @@
}
},
"resources": {
"description": "The app's resources to package. This a list of either a path to a resource (with optional glob pattern) or an object of `src` and `target` paths.\n\n## Format-specific:\n\n- **[PackageFormat::Nsis] / [PackageFormat::Wix]**: The resources are placed next to the executable in the root of the packager. - **[PackageFormat::Deb]**: The resources are placed in `usr/lib` of the package.",
"description": "The app's resources to package. This a list of either a glob pattern, path to a file, path to a directory or an object of `src` and `target` paths. In the case of using an object, the `src` could be either a glob pattern, path to a file, path to a directory, and the `target` is a path inside the final resources folder in the installed package.\n\n## Format-specific:\n\n- **[PackageFormat::Nsis] / [PackageFormat::Wix]**: The resources are placed next to the executable in the root of the packager. - **[PackageFormat::Deb]**: The resources are placed in `usr/lib` of the package.",
"type": [
"array",
"null"
Expand Down
105 changes: 63 additions & 42 deletions crates/packager/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,8 @@ impl ConfigExt for Config {
pub(crate) trait ConfigExtInternal {
fn main_binary(&self) -> crate::Result<&Binary>;
fn main_binary_name(&self) -> crate::Result<&String>;
fn resources_from_dir(src_dir: &PathBuf, target_dir: &Path) -> crate::Result<Vec<IResource>>;
fn resources_from_glob(glob: &str) -> crate::Result<Vec<IResource>>;
fn resources(&self) -> crate::Result<Vec<IResource>>;
fn find_ico(&self) -> Option<PathBuf>;
fn copy_resources(&self, path: &Path) -> crate::Result<()>;
Expand All @@ -119,58 +121,66 @@ impl ConfigExtInternal for Config {
.ok_or_else(|| crate::Error::MainBinaryNotFound)
}

fn resources(&self) -> crate::Result<Vec<IResource>> {
if let Some(resources) = &self.resources {
let cwd = std::env::current_dir()?;
let cwd = dunce::simplified(&cwd);

#[inline]
fn create_resources_from_dir(
src: &PathBuf,
target: &Path,
) -> crate::Result<Vec<IResource>> {
let mut out = Vec::new();
for entry in walkdir::WalkDir::new(src) {
let entry = entry?;
let path = entry.path();
if path.is_file() {
let relative = path.relative_to(src)?.to_path("");
let resource = IResource {
src: dunce::canonicalize(path)?,
target: target.join(relative),
};
out.push(resource);
}
}
Ok(out)
#[inline]
fn resources_from_dir(src_dir: &PathBuf, target_dir: &Path) -> crate::Result<Vec<IResource>> {
let mut out = Vec::new();
for entry in walkdir::WalkDir::new(src_dir) {
let entry = entry?;
let path = entry.path();
if path.is_file() {
let relative = path.relative_to(src_dir)?.to_path("");
let resource = IResource {
src: dunce::canonicalize(path)?,
target: target_dir.join(relative),
};
out.push(resource);
}
}
Ok(out)
}

#[inline]
fn resources_from_glob(glob: &str) -> crate::Result<Vec<IResource>> {
let mut out = Vec::new();
for src in glob::glob(glob).unwrap() {
let src = dunce::canonicalize(src?)?;
let target = PathBuf::from(src.file_name().unwrap());
out.push(IResource { src, target })
}
Ok(out)
}

fn resources(&self) -> crate::Result<Vec<IResource>> {
if let Some(resources) = &self.resources {
let mut out = Vec::new();
for r in resources {
match r {
Resource::Single(src) => {
let src_p = PathBuf::from(src);
if src_p.is_dir() {
out.extend(create_resources_from_dir(&src_p, &src_p)?);
let src_dir = PathBuf::from(src);
if src_dir.is_dir() {
let target_dir = Path::new(src_dir.file_name().unwrap());
out.extend(Self::resources_from_dir(&src_dir, target_dir)?);
} else {
for src in glob::glob(src).unwrap() {
let src = src?;
let src = dunce::canonicalize(src)?;
let target = src.relative_to(cwd)?;
out.push(IResource {
src,
target: target.to_path(""),
})
}
out.extend(Self::resources_from_glob(&src)?);
}
}
Resource::Mapped { src, target } => {
let src = dunce::canonicalize(src)?;
let target = PathBuf::from(target);
if src.is_file() {
out.push(IResource { src, target })
} else if src.is_dir() {
out.extend(create_resources_from_dir(&src, &target)?);
let src_path = PathBuf::from(src);
let target_dir = sanitize_path(target);
if src_path.is_dir() {
out.extend(Self::resources_from_dir(&src_path, &target_dir)?);
} else if src_path.is_file() {
out.push(IResource {
src: dunce::canonicalize(src_path)?,
target: sanitize_path(target),
});
} else {
let globbed_res = Self::resources_from_glob(&src)?;
let retargetd_res = globbed_res.into_iter().map(|mut r| {
r.target = target_dir.join(r.target);
r
});
out.extend(retargetd_res);
}
}
}
Expand Down Expand Up @@ -224,3 +234,14 @@ impl ConfigExtInternal for Config {
Ok(())
}
}

fn sanitize_path<P: AsRef<Path>>(path: P) -> PathBuf {
let mut dest = PathBuf::new();
for c in path.as_ref().components() {
match c {
std::path::Component::Normal(s) => dest.push(s),
_ => {}
}
}
dest
}
8 changes: 6 additions & 2 deletions crates/packager/src/nsis/installer.nsi
Original file line number Diff line number Diff line change
Expand Up @@ -468,10 +468,14 @@ Section Install
${GetSize} "$INSTDIR" "/M=${MAINBINARYNAME}.exe /S=0B" $0 $1 $2
IntOp $AppSize $AppSize + $0

; Create resources directory structure
{{#each resources_dirs}}
CreateDirectory "$INSTDIR\\{{this}}"
{{/each}}

; Copy resources
{{#each resources}}
CreateDirectory "$INSTDIR\\{{this.[0]}}"
File /a "/oname={{this.[1]}}" "{{@key}}"
File /a "/oname={{this.[1]}}" "{{this.[0]}}"
${GetSize} "$INSTDIR" "/M={{this.[1]}} /S=0B" $0 $1 $2
IntOp $AppSize $AppSize + $0
{{/each}}
Expand Down
49 changes: 22 additions & 27 deletions crates/packager/src/nsis/mod.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use std::{
collections::{BTreeMap, HashMap},
collections::{BTreeMap, BTreeSet, HashMap},
path::{Path, PathBuf},
process::Command,
};
Expand Down Expand Up @@ -42,25 +42,21 @@ const NSIS_REQUIRED_FILES: &[&str] = &[
"Plugins/x86-unicode/nsis_tauri_utils.dll",
];

/// BTreeMap<OriginalPath, (ParentOfTargetPath, TargetPath)>
type ResourcesMap = BTreeMap<PathBuf, (String, PathBuf)>;
fn generate_resource_data(config: &Config) -> crate::Result<ResourcesMap> {
let mut resources_map = ResourcesMap::new();
for resource in config.resources()? {
resources_map.insert(
resource.src,
(
resource
.target
.parent()
.map(|p| p.to_string_lossy().to_string())
.unwrap_or_default(),
resource.target,
),
fn generate_resource_data(
config: &Config,
) -> crate::Result<(BTreeSet<PathBuf>, Vec<(PathBuf, PathBuf)>)> {
let mut directories = BTreeSet::new();
let mut resources_map = Vec::new();
for r in config.resources()? {
directories.insert(
r.target
.parent()
.unwrap_or_else(|| Path::new(""))
.to_path_buf(),
);
resources_map.push((r.src, r.target))
}

Ok(resources_map)
Ok((directories, resources_map))
}

/// BTreeMap<OriginalPath, TargetFileName>
Expand All @@ -84,14 +80,12 @@ fn generate_binaries_data(config: &Config) -> crate::Result<BinariesMap> {
for bin in &config.binaries {
if !bin.main {
let bin_path = config.binary_path(bin);
binaries.insert(
bin_path.clone(),
bin_path
.file_name()
.expect("failed to extract binary filename")
.to_string_lossy()
.to_string(),
);
let dest_filename = bin_path
.file_name()
.expect("failed to extract binary filename")
.to_string_lossy()
.to_string();
binaries.insert(bin_path, dest_filename);
}
}

Expand Down Expand Up @@ -390,7 +384,8 @@ fn build_nsis_app_installer(
let out_file = "nsis-output.exe";
data.insert("out_file", to_json(out_file));

let resources = generate_resource_data(config)?;
let (resources_dirs, resources) = generate_resource_data(config)?;
data.insert("resources_dirs", to_json(resources_dirs));
data.insert("resources", to_json(resources));

let binaries = generate_binaries_data(config)?;
Expand Down
32 changes: 1 addition & 31 deletions crates/packager/src/wix/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -318,36 +318,6 @@ fn generate_resource_data(config: &Config) -> crate::Result<ResourceMap> {
directory_entry.add_file(resource_entry);
}

let mut dlls = Vec::new();

for dll in glob::glob(
config
.out_dir()
.join("*.dll")
.to_string_lossy()
.to_string()
.as_str(),
)? {
let path = dll?;
dlls.push(ResourceFile {
id: format!("I{}", Uuid::new_v4().as_simple()),
guid: Uuid::new_v4().to_string(),
path: dunce::simplified(&path).to_path_buf(),
});
}

if !dlls.is_empty() {
resources_map.insert(
"".to_string(),
ResourceDirectory {
path: "".to_string(),
name: "".to_string(),
directories: vec![],
files: dlls,
},
);
}

Ok(resources_map)
}

Expand Down Expand Up @@ -564,7 +534,7 @@ fn build_wix_app_installer(
data.insert("resources", to_json(resources_wix_string));
data.insert("resource_file_ids", to_json(files_ids));

// TODO: how to choose to include merge modules
// TODO: how to include merge modules

data.insert(
"app_exe_source",
Expand Down
6 changes: 4 additions & 2 deletions examples/tauri/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,12 @@ product-name = "Tauri example"
identifier = "com.tauri.example"
resources = [
"Cargo.toml",
"README.md",
"../../README.md",
"icons/*",
"src",
{ src = "src-ui", target = "public" },
{ src = "src-ui/assets/tauri.svg", target = "path/to/tauri.svg" },
{ src = "src-ui", target = "path/to/src-ui" },
{ src = "src-ui/assets/*", target = "public" },
]
icons = [
"icons/32x32.png",
Expand Down

0 comments on commit 967bf35

Please sign in to comment.