desktop: Add HTTP Referer and Cookie (#16424)

This commit is contained in:
Marco Bartoli 2024-05-25 00:07:36 +02:00 committed by GitHub
parent 3aa7c07e95
commit e1f014ea85
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 97 additions and 1 deletions

View File

@ -5,6 +5,8 @@ movie-parameters = Movie Parameters
custom-base-url = Custom Base URL
spoof-swf-url = Spoof SWF URL
referer-url = Referer URL
cookie = Cookie
proxy = Proxy

View File

@ -149,6 +149,15 @@ pub struct Opt {
#[clap(long, value_parser)]
pub spoof_url: Option<Url>,
/// Spoofs the HTTP referer header.
#[clap(long, value_parser)]
pub referer: Option<Url>,
/// Spoofs the HTTP cookie header.
/// This is a string of the form "name1=value1; name2=value2".
#[clap(long)]
pub cookie: Option<String>,
/// The version of the player to emulate
#[clap(long)]
pub player_version: Option<u8>,

View File

@ -23,6 +23,8 @@ pub struct OpenDialog {
// These are outside of PlayerOptions as it can be an invalid value (ie URL) during typing,
// and we don't want to clear the value if the user, ie, toggles the checkbox.
spoof_url: OptionalField<UrlField>,
referer: OptionalField<UrlField>,
cookie: OptionalField<CookieField>,
base_url: OptionalField<UrlField>,
proxy_url: OptionalField<UrlField>,
path: PathOrUrlField,
@ -53,6 +55,14 @@ impl OpenDialog {
defaults.player.spoof_url.as_ref().map(Url::to_string),
UrlField::new("https://example.org/game.swf"),
);
let referer = OptionalField::new(
defaults.player.referer.as_ref().map(Url::to_string),
UrlField::new("https://example.org"),
);
let cookie = OptionalField::new(
defaults.player.cookie.clone(),
CookieField::new("value1=cookie1; value2=cookie2"),
);
let base_url = OptionalField::new(
defaults.player.base.as_ref().map(Url::to_string),
UrlField::new("https://example.org"),
@ -242,6 +252,8 @@ impl OpenDialog {
options: defaults,
event_loop,
spoof_url,
referer,
cookie,
base_url,
proxy_url,
path,
@ -354,6 +366,20 @@ impl OpenDialog {
.is_valid();
ui.end_row();
ui.label(text(locale, "referer-url"));
is_valid &= self
.referer
.ui(ui, &mut self.options.player.referer, locale)
.is_valid();
ui.end_row();
ui.label(text(locale, "cookie"));
is_valid &= self
.cookie
.ui(ui, &mut self.options.player.cookie, locale)
.is_valid();
ui.end_row();
ui.label(text(locale, "proxy"));
is_valid &= self
.proxy_url
@ -594,6 +620,40 @@ impl InnerField for UrlField {
}
}
struct CookieField {
hint: &'static str,
}
impl CookieField {
pub fn new(hint: &'static str) -> Self {
Self { hint }
}
}
impl InnerField for CookieField {
type Value = String;
type Result = String;
fn value_if_missing(&self) -> Self::Value {
String::new()
}
fn ui(&self, ui: &mut Ui, value: &mut Self::Value, error: bool, _locale: &LanguageIdentifier) {
TextEdit::singleline(value)
.hint_text(self.hint)
.text_color_opt(if error {
Some(ui.style().visuals.error_fg_color)
} else {
None
})
.ui(ui);
}
fn value_to_result(&self, value: &Self::Value) -> Result<Self::Result, ()> {
Ok(value.clone())
}
}
struct DurationField {
range: RangeInclusive<f64>,
default_seconds: f64,

View File

@ -75,6 +75,8 @@ impl From<&GlobalPreferences> for LaunchOptions {
load_behavior: value.cli.load_behavior,
letterbox: value.cli.letterbox,
spoof_url: value.cli.spoof_url.clone(),
referer: value.cli.referer.clone(),
cookie: value.cli.cookie.clone(),
player_version: value.cli.player_version,
player_runtime: value.cli.player_runtime,
frame_rate: value.cli.frame_rate,
@ -192,6 +194,8 @@ impl ActivePlayer {
.base
.to_owned()
.unwrap_or_else(|| movie_url.clone()),
opt.player.referer.clone(),
opt.player.cookie.clone(),
future_spawner,
opt.proxy.clone(),
opt.player.upgrade_to_https.unwrap_or_default(),

View File

@ -9,7 +9,7 @@ use async_net::TcpStream;
use futures::future::select;
use futures::{AsyncReadExt, AsyncWriteExt};
use futures_lite::FutureExt;
use reqwest::Proxy;
use reqwest::{cookie, header, Proxy};
use ruffle_core::backend::navigator::{
async_return, create_fetch_error, ErrorResponse, NavigationMethod, NavigatorBackend,
OpenURLMode, OwnedFuture, Request, SocketMode, SuccessResponse,
@ -70,6 +70,8 @@ impl<F: FutureSpawner, I: NavigatorInterface> ExternalNavigatorBackend<F, I> {
#[allow(clippy::too_many_arguments)]
pub fn new(
mut base_url: Url,
referer: Option<Url>,
cookie: Option<String>,
future_spawner: F,
proxy: Option<Url>,
upgrade_to_https: bool,
@ -81,6 +83,19 @@ impl<F: FutureSpawner, I: NavigatorInterface> ExternalNavigatorBackend<F, I> {
) -> Self {
let mut builder = reqwest::ClientBuilder::new().cookie_store(true);
if let Some(referer) = referer {
let mut headers = header::HeaderMap::new();
headers.insert(header::REFERER, referer.to_string().parse().unwrap());
builder = builder.default_headers(headers);
}
if let Some(cookie) = cookie {
let cookie_jar = cookie::Jar::default();
cookie_jar.add_cookie_str(&cookie, &base_url);
let cookie_store = std::sync::Arc::new(cookie_jar);
builder = builder.cookie_provider(cookie_store)
}
if let Some(proxy) = proxy {
match Proxy::all(proxy.clone()) {
Ok(proxy) => {
@ -535,6 +550,8 @@ mod tests {
let url = Url::parse("https://example.com/path/").unwrap();
ExternalNavigatorBackend::new(
url.clone(),
None,
None,
TestFutureSpawner,
None,
false,

View File

@ -21,6 +21,8 @@ pub struct PlayerOptions {
pub load_behavior: Option<LoadBehavior>,
pub letterbox: Option<Letterbox>,
pub spoof_url: Option<Url>,
pub referer: Option<Url>,
pub cookie: Option<String>,
pub player_version: Option<u8>,
pub player_runtime: Option<PlayerRuntime>,
pub frame_rate: Option<f64>,
@ -44,6 +46,8 @@ impl PlayerOptions {
load_behavior: self.load_behavior.or(other.load_behavior),
letterbox: self.letterbox.or(other.letterbox),
spoof_url: self.spoof_url.clone().or_else(|| other.spoof_url.clone()),
referer: self.referer.clone().or_else(|| other.referer.clone()),
cookie: self.cookie.clone().or_else(|| other.cookie.clone()),
player_version: self.player_version.or(other.player_version),
player_runtime: self.player_runtime.or(other.player_runtime),
frame_rate: self.frame_rate.or(other.frame_rate),