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
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
|
//! Helper types and functions to allow configuring hidden files visibility
//! for WebDAV handlers
use dav_server::{davpath::DavPath, fs::*, localfs::LocalFs};
use futures::{future::ready, StreamExt, TryFutureExt};
use std::path::{Component, Path};
/// A dav_server local filesystem backend that can be configured to deny access
/// to files and directories with names starting with a dot.
#[derive(Clone)]
pub struct RestrictedFs {
local: Box<LocalFs>,
show_hidden: bool,
}
impl RestrictedFs {
/// Creates a new RestrictedFs serving the local path at "base".
/// If "show_hidden" is false, access to hidden files is prevented.
pub fn new<P: AsRef<Path>>(base: P, show_hidden: bool) -> Box<RestrictedFs> {
let local = LocalFs::new(base, false, false, false);
Box::new(RestrictedFs { local, show_hidden })
}
}
/// true if any normal component of path either starts with dot or can't be turned into a str
fn path_has_hidden_components(path: &DavPath) -> bool {
path.as_pathbuf().components().any(|c| match c {
Component::Normal(name) => name.to_str().is_none_or(|s| s.starts_with('.')),
_ => false,
})
}
impl DavFileSystem for RestrictedFs {
fn open<'a>(
&'a self,
path: &'a DavPath,
options: OpenOptions,
) -> FsFuture<'a, Box<dyn DavFile>> {
if !path_has_hidden_components(path) || self.show_hidden {
self.local.open(path, options)
} else {
Box::pin(ready(Err(FsError::NotFound)))
}
}
fn read_dir<'a>(
&'a self,
path: &'a DavPath,
meta: ReadDirMeta,
) -> FsFuture<'a, FsStream<Box<dyn DavDirEntry>>> {
if self.show_hidden {
self.local.read_dir(path, meta)
} else if !path_has_hidden_components(path) {
Box::pin(self.local.read_dir(path, meta).map_ok(|stream| {
let dyn_stream: FsStream<Box<dyn DavDirEntry>> = Box::pin(stream.filter(|entry| {
ready(match entry {
Ok(ref e) => !e.name().starts_with(b"."),
_ => false,
})
}));
dyn_stream
}))
} else {
Box::pin(ready(Err(FsError::NotFound)))
}
}
fn metadata<'a>(&'a self, path: &'a DavPath) -> FsFuture<'a, Box<dyn DavMetaData>> {
if !path_has_hidden_components(path) || self.show_hidden {
self.local.metadata(path)
} else {
Box::pin(ready(Err(FsError::NotFound)))
}
}
fn symlink_metadata<'a>(&'a self, path: &'a DavPath) -> FsFuture<'a, Box<dyn DavMetaData>> {
if !path_has_hidden_components(path) || self.show_hidden {
self.local.symlink_metadata(path)
} else {
Box::pin(ready(Err(FsError::NotFound)))
}
}
}
|