desktop: Implement asking for permission before accessing files
This implements the filesystem access mode setting and its three options. When set to Ask, the filesystem access dialog will be shown to the user.
This commit is contained in:
parent
61c4005785
commit
6b6c4d4909
|
@ -3,13 +3,17 @@ use ruffle_frontend_utils::backends::navigator::NavigatorInterface;
|
|||
use std::fs::File;
|
||||
use std::io;
|
||||
use std::io::ErrorKind;
|
||||
use std::path::Path;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::sync::{Arc, Mutex};
|
||||
use tokio::sync::oneshot;
|
||||
use url::Url;
|
||||
use winit::event_loop::EventLoopProxy;
|
||||
|
||||
use crate::cli::FilesystemAccessMode;
|
||||
use crate::custom_event::RuffleEvent;
|
||||
use crate::gui::dialogs::filesystem_access_dialog::{
|
||||
FilesystemAccessDialogConfiguration, FilesystemAccessDialogResult,
|
||||
};
|
||||
use crate::gui::dialogs::network_access_dialog::{
|
||||
NetworkAccessDialogConfiguration, NetworkAccessDialogResult,
|
||||
};
|
||||
|
@ -20,14 +24,46 @@ use crate::util::open_url;
|
|||
pub struct DesktopNavigatorInterface {
|
||||
// Arc + Mutex due to macOS
|
||||
event_loop: Arc<Mutex<EventLoopProxy<RuffleEvent>>>,
|
||||
|
||||
filesystem_access_mode: FilesystemAccessMode,
|
||||
|
||||
// TODO Make this more generic, maybe a manager?
|
||||
allowed_paths: Arc<Mutex<Vec<PathBuf>>>,
|
||||
}
|
||||
|
||||
impl DesktopNavigatorInterface {
|
||||
pub fn new(event_loop: EventLoopProxy<RuffleEvent>) -> Self {
|
||||
pub fn new(
|
||||
event_loop: EventLoopProxy<RuffleEvent>,
|
||||
movie_path: Option<PathBuf>,
|
||||
filesystem_access_mode: FilesystemAccessMode,
|
||||
) -> Self {
|
||||
Self {
|
||||
event_loop: Arc::new(Mutex::new(event_loop)),
|
||||
allowed_paths: Arc::new(Mutex::new(if let Some(movie_path) = movie_path {
|
||||
vec![movie_path]
|
||||
} else {
|
||||
Vec::new()
|
||||
})),
|
||||
filesystem_access_mode,
|
||||
}
|
||||
}
|
||||
|
||||
async fn ask_for_filesystem_access(&self, path: &Path) -> bool {
|
||||
let (notifier, receiver) = oneshot::channel();
|
||||
let _ = self
|
||||
.event_loop
|
||||
.lock()
|
||||
.expect("Non-poisoned event loop")
|
||||
.send_event(RuffleEvent::OpenDialog(DialogDescriptor::FilesystemAccess(
|
||||
FilesystemAccessDialogConfiguration::new(
|
||||
notifier,
|
||||
self.allowed_paths.clone(),
|
||||
path.to_path_buf(),
|
||||
),
|
||||
)));
|
||||
|
||||
receiver.await == Ok(FilesystemAccessDialogResult::Allow)
|
||||
}
|
||||
}
|
||||
|
||||
impl NavigatorInterface for DesktopNavigatorInterface {
|
||||
|
@ -45,6 +81,18 @@ impl NavigatorInterface for DesktopNavigatorInterface {
|
|||
}
|
||||
|
||||
async fn open_file(&self, path: &Path) -> io::Result<File> {
|
||||
let path = &path.canonicalize()?;
|
||||
|
||||
let allow = match self.filesystem_access_mode {
|
||||
FilesystemAccessMode::Allow => true,
|
||||
FilesystemAccessMode::Deny => false,
|
||||
FilesystemAccessMode::Ask => self.ask_for_filesystem_access(path).await,
|
||||
};
|
||||
|
||||
if !allow {
|
||||
return Err(ErrorKind::PermissionDenied.into());
|
||||
}
|
||||
|
||||
File::open(path).or_else(|e| {
|
||||
if cfg!(feature = "sandbox") {
|
||||
use rfd::FileDialog;
|
||||
|
|
|
@ -2,6 +2,7 @@ use crate::backends::{
|
|||
CpalAudioBackend, DesktopExternalInterfaceProvider, DesktopFSCommandProvider,
|
||||
DesktopNavigatorInterface, DesktopUiBackend,
|
||||
};
|
||||
use crate::cli::FilesystemAccessMode;
|
||||
use crate::custom_event::RuffleEvent;
|
||||
use crate::gui::{FilePicker, MovieView};
|
||||
use crate::preferences::GlobalPreferences;
|
||||
|
@ -45,6 +46,7 @@ pub struct LaunchOptions {
|
|||
pub save_directory: PathBuf,
|
||||
pub cache_directory: PathBuf,
|
||||
pub open_url_mode: OpenURLMode,
|
||||
pub filesystem_access_mode: FilesystemAccessMode,
|
||||
pub gamepad_button_mapping: HashMap<GamepadButton, KeyCode>,
|
||||
pub avm2_optimizer_enabled: bool,
|
||||
}
|
||||
|
@ -93,6 +95,7 @@ impl From<&GlobalPreferences> for LaunchOptions {
|
|||
save_directory: value.cli.save_directory.clone(),
|
||||
cache_directory: value.cli.cache_directory.clone(),
|
||||
open_url_mode: value.cli.open_url_mode,
|
||||
filesystem_access_mode: value.cli.filesystem_access_mode,
|
||||
socket_allowed: HashSet::from_iter(value.cli.socket_allow.iter().cloned()),
|
||||
tcp_connections: value.cli.tcp_connections,
|
||||
gamepad_button_mapping: HashMap::from_iter(value.cli.gamepad_button.iter().cloned()),
|
||||
|
@ -198,6 +201,7 @@ impl ActivePlayer {
|
|||
save_directory: opt.save_directory.clone(),
|
||||
cache_directory: opt.cache_directory.clone(),
|
||||
open_url_mode: opt.open_url_mode,
|
||||
filesystem_access_mode: opt.filesystem_access_mode,
|
||||
gamepad_button_mapping: opt.gamepad_button_mapping.clone(),
|
||||
avm2_optimizer_enabled: opt.avm2_optimizer_enabled,
|
||||
})
|
||||
|
@ -221,7 +225,11 @@ impl ActivePlayer {
|
|||
opt.socket_allowed.clone(),
|
||||
opt.tcp_connections.unwrap_or(SocketMode::Ask),
|
||||
Rc::new(content),
|
||||
DesktopNavigatorInterface::new(event_loop.clone()),
|
||||
DesktopNavigatorInterface::new(
|
||||
event_loop.clone(),
|
||||
movie_url.to_file_path().ok(),
|
||||
opt.filesystem_access_mode,
|
||||
),
|
||||
);
|
||||
|
||||
if cfg!(feature = "external_video") && preferences.openh264_enabled() {
|
||||
|
|
Loading…
Reference in New Issue