From 8f2292c2c75bdd217ee357b311044807c52b718a Mon Sep 17 00:00:00 2001 From: Daniel Jacobs Date: Tue, 16 Jan 2024 11:05:05 -0500 Subject: [PATCH] core: Add error for loading invalid SWF files and display as appropriate --- core/src/backend/ui.rs | 4 ++-- core/src/loader.rs | 4 ++-- desktop/src/backends/ui.rs | 2 +- tests/framework/src/backends/ui.rs | 2 +- web/packages/core/src/ruffle-player.ts | 21 ++++++++++++++++----- web/packages/core/texts/en-US/messages.ftl | 3 +++ web/src/lib.rs | 12 +++++++++--- web/src/ui.rs | 5 +++-- 8 files changed, 37 insertions(+), 16 deletions(-) diff --git a/core/src/backend/ui.rs b/core/src/backend/ui.rs index 7918ae0a2..eb4a52eff 100644 --- a/core/src/backend/ui.rs +++ b/core/src/backend/ui.rs @@ -81,7 +81,7 @@ pub trait UiBackend: Downcast { /// Displays a message about an error during root movie download. /// In particular, on web this can be a CORS error, which we can sidestep /// by providing a direct .swf link instead. - fn display_root_movie_download_failed_message(&self); + fn display_root_movie_download_failed_message(&self, _invalid_swf: bool); // Unused, but kept in case we need it later. fn message(&self, message: &str); @@ -275,7 +275,7 @@ impl UiBackend for NullUiBackend { Ok(()) } - fn display_root_movie_download_failed_message(&self) {} + fn display_root_movie_download_failed_message(&self, _invalid_swf: bool) {} fn message(&self, _message: &str) {} diff --git a/core/src/loader.rs b/core/src/loader.rs index d0796209e..0dd72f171 100644 --- a/core/src/loader.rs +++ b/core/src/loader.rs @@ -821,7 +821,7 @@ impl<'gc> Loader<'gc> { .lock() .unwrap() .ui() - .display_root_movie_download_failed_message(); + .display_root_movie_download_failed_message(false); error.error })?; @@ -844,7 +844,7 @@ impl<'gc> Loader<'gc> { .lock() .unwrap() .ui() - .display_root_movie_download_failed_message(); + .display_root_movie_download_failed_message(true); error })?; on_metadata(movie.header()); diff --git a/desktop/src/backends/ui.rs b/desktop/src/backends/ui.rs index 18f281c1a..ddc8476e7 100644 --- a/desktop/src/backends/ui.rs +++ b/desktop/src/backends/ui.rs @@ -196,7 +196,7 @@ impl UiBackend for DesktopUiBackend { Ok(()) } - fn display_root_movie_download_failed_message(&self) { + fn display_root_movie_download_failed_message(&self, _invalid_swf: bool) { let dialog = MessageDialog::new() .set_level(MessageLevel::Warning) .set_title("Ruffle - Load failed") diff --git a/tests/framework/src/backends/ui.rs b/tests/framework/src/backends/ui.rs index 9232c759d..25c1d23be 100644 --- a/tests/framework/src/backends/ui.rs +++ b/tests/framework/src/backends/ui.rs @@ -113,7 +113,7 @@ impl UiBackend for TestUiBackend { Ok(()) } - fn display_root_movie_download_failed_message(&self) {} + fn display_root_movie_download_failed_message(&self, _invalid_swf: bool) {} fn message(&self, _message: &str) {} diff --git a/web/packages/core/src/ruffle-player.ts b/web/packages/core/src/ruffle-player.ts index cceeb54e6..3711c9bc2 100644 --- a/web/packages/core/src/ruffle-player.ts +++ b/web/packages/core/src/ruffle-player.ts @@ -35,6 +35,7 @@ enum PanicError { WasmMimeType, WasmNotFound, WasmDisabledMicrosoftEdge, + InvalidSwf, SwfFetchError, SwfCors, } @@ -2114,6 +2115,10 @@ export class RufflePlayer extends HTMLElement { new PanicLinkInfo(), ]); break; + case PanicError.InvalidSwf: + errorBody = textAsParagraphs("error-invalid-swf"); + errorFooter = this.createErrorFooter([new PanicLinkInfo()]); + break; case PanicError.SwfFetchError: errorBody = textAsParagraphs("error-swf-fetch"); errorFooter = this.createErrorFooter([new PanicLinkInfo()]); @@ -2244,10 +2249,14 @@ export class RufflePlayer extends HTMLElement { this.destroy(); } - protected displayRootMovieDownloadFailedMessage(): void { + protected displayRootMovieDownloadFailedMessage(invalidSwf: boolean): void { const openInNewTab = this.loadedConfig?.openInNewTab; - if (openInNewTab && window.location.origin !== this.swfUrl!.origin) { - const url = new URL(this.swfUrl!); + if ( + openInNewTab && + this.swfUrl && + window.location.origin !== this.swfUrl.origin + ) { + const url = new URL(this.swfUrl); if (this.loadedConfig?.parameters) { const parameters = sanitizeParameters( this.loadedConfig?.parameters, @@ -2275,10 +2284,12 @@ export class RufflePlayer extends HTMLElement { this.container.prepend(div); } else { const error = new Error("Failed to fetch: " + this.swfUrl); - if (!this.swfUrl!.protocol.includes("http")) { + if (this.swfUrl && !this.swfUrl.protocol.includes("http")) { error.ruffleIndexError = PanicError.FileProtocol; + } else if (invalidSwf) { + error.ruffleIndexError = PanicError.InvalidSwf; } else if ( - window.location.origin === this.swfUrl!.origin || + window.location.origin === this.swfUrl?.origin || // The extension's internal player page is not restricted by CORS window.location.protocol.includes("extension") ) { diff --git a/web/packages/core/texts/en-US/messages.ftl b/web/packages/core/texts/en-US/messages.ftl index ab3a93294..ff283b8e1 100644 --- a/web/packages/core/texts/en-US/messages.ftl +++ b/web/packages/core/texts/en-US/messages.ftl @@ -30,6 +30,9 @@ error-wasm-mime-type = Ruffle has encountered a major issue whilst trying to initialize. This web server is not serving ".wasm" files with the correct MIME type. If you are the server administrator, please consult the Ruffle wiki for help. +error-invalid-swf = + Ruffle cannot parse the requested file. + The most likely reason is that the requested file is not a valid SWF. error-swf-fetch = Ruffle failed to load the Flash SWF file. The most likely reason is that the file no longer exists, so there is nothing for Ruffle to load. diff --git a/web/src/lib.rs b/web/src/lib.rs index d6d2f74fc..f9903eaa1 100644 --- a/web/src/lib.rs +++ b/web/src/lib.rs @@ -105,7 +105,7 @@ extern "C" { fn panic(this: &JavascriptPlayer, error: &JsError); #[wasm_bindgen(method, js_name = "displayRootMovieDownloadFailedMessage")] - fn display_root_movie_download_failed_message(this: &JavascriptPlayer); + fn display_root_movie_download_failed_message(this: &JavascriptPlayer, invalid_swf: bool); #[wasm_bindgen(method, js_name = "displayMessage")] fn display_message(this: &JavascriptPlayer, message: &str); @@ -401,8 +401,14 @@ impl Ruffle { segments.push(&swf_name); } - let mut movie = SwfMovie::from_data(&swf_data.to_vec(), url.to_string(), None) - .map_err(|e| format!("Error loading movie: {e}"))?; + let mut movie = + SwfMovie::from_data(&swf_data.to_vec(), url.to_string(), None).map_err(|e| { + let _ = self.with_core_mut(|core| { + core.ui_mut() + .display_root_movie_download_failed_message(true); + }); + format!("Error loading movie: {e}") + })?; movie.append_parameters(parse_movie_parameters(¶meters)); self.on_metadata(movie.header()); diff --git a/web/src/ui.rs b/web/src/ui.rs index 48a82f4a0..af42ddc94 100644 --- a/web/src/ui.rs +++ b/web/src/ui.rs @@ -240,8 +240,9 @@ impl UiBackend for WebUiBackend { } } - fn display_root_movie_download_failed_message(&self) { - self.js_player.display_root_movie_download_failed_message() + fn display_root_movie_download_failed_message(&self, invalid_swf: bool) { + self.js_player + .display_root_movie_download_failed_message(invalid_swf) } fn message(&self, message: &str) {