1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
// This file is part of helpers4.
// Copyright (C) 2025 baxyz
// SPDX-License-Identifier: LGPL-3.0-or-later
use parts;
use ;
/// Whether `path`, taken relative to `base`, stays inside `base`: a guard against path traversal.
///
/// A relative `path` is joined to `base` and both are cleaned lexically (see
/// [`normalize`](super::normalize)), so `"a/../../b"` escapes and `"a/../b"` does not; an
/// absolute `path` must itself lie under `base`. `base` counts as inside itself. Nothing touches
/// the file system, so this does **not** see symbolic links: if the directory can contain links
/// an attacker controls, resolve the path with [`std::fs::canonicalize`] and compare that instead.
///
/// # Arguments
///
/// - `base` - The directory that must contain the result.
/// - `path` - The path to check, relative to `base` or absolute.
///
/// # Returns
///
/// `true` when the cleaned path is `base` or lies under it.
///
/// # Examples
///
/// ```
/// use helpers4::fs::is_within;
/// use std::path::Path;
///
/// let uploads = Path::new("/srv/uploads");
/// assert!(is_within(uploads, Path::new("avatars/me.png")));
/// assert!(!is_within(uploads, Path::new("../secrets.txt")));
/// assert!(!is_within(uploads, Path::new("/etc/passwd")));
/// ```