mirror of
https://github.com/euzu/tuliprox.git
synced 2026-10-04 15:02:16 +02:00
Fix/catchup (#778)
* Fix: setting auth web_ui token_ttl_mins = 0 fixed. * Fix: catchup * New: added playlist update log view * Fix: Landing Page New: "Last Page" added for Landing Page selection
This commit is contained in:
@@ -167,8 +167,8 @@ pub struct WebUiConfigDto {
|
||||
pub kick_secs: u64,
|
||||
#[serde(default, skip_serializing_if = "is_false")]
|
||||
pub combine_views_stats_streams: bool,
|
||||
#[serde(default, skip_serializing_if = "ViewType::is_default")]
|
||||
pub landing_page: ViewType,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub landing_page: Option<ViewType>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub stream_info: Option<StreamInfoConfigDto>,
|
||||
}
|
||||
@@ -184,7 +184,7 @@ impl Default for WebUiConfigDto {
|
||||
player_server: None,
|
||||
kick_secs: default_kick_secs(),
|
||||
combine_views_stats_streams: false,
|
||||
landing_page: ViewType::default(),
|
||||
landing_page: None,
|
||||
stream_info: None,
|
||||
}
|
||||
}
|
||||
@@ -196,7 +196,7 @@ impl WebUiConfigDto {
|
||||
self.enabled == empty.enabled
|
||||
&& self.user_ui_enabled == empty.user_ui_enabled
|
||||
&& !self.combine_views_stats_streams
|
||||
&& self.landing_page == ViewType::default()
|
||||
&& self.landing_page.is_none()
|
||||
&& is_blank_or_default_web_ui_path(&self.path)
|
||||
&& is_blank_optional_str(self.player_server.as_deref())
|
||||
&& self.kick_secs == default_kick_secs()
|
||||
@@ -302,4 +302,18 @@ mod tests {
|
||||
assert!(dto.stream_info.is_none());
|
||||
assert!(dto.is_empty());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn web_ui_config_dto_default_uses_last_page_landing_page() {
|
||||
let dto = WebUiConfigDto::default();
|
||||
|
||||
assert_eq!(dto.landing_page, None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn web_ui_config_dto_is_not_empty_when_explicit_landing_page_is_set() {
|
||||
let dto = WebUiConfigDto { landing_page: Some(ViewType::Streams), ..WebUiConfigDto::default() };
|
||||
|
||||
assert!(!dto.is_empty());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@ mod playlist_document;
|
||||
mod playlist_info_document;
|
||||
mod playlist_request;
|
||||
mod processing_order;
|
||||
mod progress;
|
||||
mod regex_cache;
|
||||
mod search_request;
|
||||
mod short_epg;
|
||||
@@ -45,7 +46,7 @@ pub use self::{
|
||||
active_user_connection_change::*, auth::*, cluster_flags::*, config::*, download::*, epg::*, epg_request::*,
|
||||
ip_check::*, item_field::*, library_request::*, mapping::*, media_properties::*, messaging::*, pagination::*,
|
||||
playlist::*, playlist_categories::*, playlist_info_document::*, playlist_request::*, processing_order::*,
|
||||
regex_cache::*, search_request::*, short_epg::*, stats::*, status_check::*, stream_history::*,
|
||||
progress::*, regex_cache::*, search_request::*, short_epg::*, stats::*, status_check::*, stream_history::*,
|
||||
stream_history_record::*, stream_info::*, stream_meter::*, stream_properties::*, strm_export_style::*,
|
||||
system_info::*, target_type::*, transfer::*, ui_playlist_item::*, user_command::*, uuidtype::*, web_socket::*,
|
||||
xtream::*,
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
use crate::model::LibraryScanSummary;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
/// Marker response for accepted long-running operations. Carries no payload:
|
||||
/// progress is delivered over the event channel, not through this response.
|
||||
#[derive(Debug, Clone, Default, Deserialize, Serialize, PartialEq, Eq)]
|
||||
pub struct OperationRunAccepted {}
|
||||
|
||||
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, Eq)]
|
||||
pub struct PlaylistUpdateProgressEvent {
|
||||
pub target: String,
|
||||
pub message: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq)]
|
||||
pub struct LibraryScanProgressEvent {
|
||||
pub summary: LibraryScanSummary,
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
use crate::model::{
|
||||
user_command::UserCommand, ActiveUserConnectionChange, ConfigType, DownloadsDelta, DownloadsResponse,
|
||||
LibraryScanSummary, PermissionSet, PlaylistUpdateState, StatusCheck, StreamMeterEntry, SystemInfo,
|
||||
LibraryScanProgressEvent, PermissionSet, PlaylistUpdateProgressEvent, PlaylistUpdateState, StatusCheck,
|
||||
StreamMeterEntry, SystemInfo,
|
||||
};
|
||||
use bytes::Bytes;
|
||||
use serde::{Deserialize, Serialize};
|
||||
@@ -92,10 +93,10 @@ pub enum ProtocolMessage {
|
||||
ActiveProviderCountResponse(usize),
|
||||
ConfigChangeResponse(ConfigType),
|
||||
PlaylistUpdateResponse(PlaylistUpdateState),
|
||||
PlaylistUpdateProgressResponse(String, String),
|
||||
PlaylistUpdateProgressResponse(PlaylistUpdateProgressEvent),
|
||||
UserActionResponse(bool),
|
||||
SystemInfoResponse(SystemInfo),
|
||||
LibraryScanProgressResponse(LibraryScanSummary),
|
||||
LibraryScanProgressResponse(LibraryScanProgressEvent),
|
||||
StreamMeterBatchResponse(Vec<StreamMeterEntry>),
|
||||
DownloadsResponse(DownloadsResponse),
|
||||
DownloadsDeltaResponse(DownloadsDelta),
|
||||
|
||||
@@ -135,7 +135,7 @@ pub static CONSTANTS: LazyLock<Constants> = LazyLock::new(|| {
|
||||
re_ipv4: Regex::new(r"\b((25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])\.){3}(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])\b").unwrap(),
|
||||
re_ipv6: Regex::new(r"\b([0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}\b|\b::([0-9a-fA-F]{1,4}:){0,6}[0-9a-fA-F]{1,4}\b|\b([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}\b|\b::ffff:(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\b").unwrap(),
|
||||
re_stream_url: Regex::new(
|
||||
r"(?i)^(?P<scheme>(?:https?|batch|provider)://)[^/]+/(?P<ctx>live|video|movie|series|m3u-stream|resource)/[^/]+/[^/]+/"
|
||||
r"(?i)^(?P<scheme>(?:https?|batch|provider)://)[^/]+/(?P<ctx>live|video|movie|series|m3u-stream|resource|timeshift|streaming|xtream|timeshift\.php)/[^/]+/[^/]+/"
|
||||
)
|
||||
.unwrap(),
|
||||
re_url: Regex::new(r"(.*://).*?/(.*)").unwrap(),
|
||||
|
||||
@@ -197,4 +197,39 @@ mod tests {
|
||||
|
||||
set_sanitize_sensitive_info(previous);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn sanitize_sensitive_info_masks_path_credentials_for_all_xtream_contexts() {
|
||||
// Regression: only `live|video|movie|series|m3u-stream|resource` were originally
|
||||
// listed in `re_stream_url`, so URLs like `/timeshift/{user}/{pass}/...` leaked
|
||||
// the username and password into log lines. The regex was extended to also
|
||||
// cover `timeshift`, `streaming`, `xtream`, and `timeshift.php`.
|
||||
let previous = super::is_sanitize_sensitive_info_enabled();
|
||||
set_sanitize_sensitive_info(true);
|
||||
|
||||
let cases: &[(&str, &str)] = &[
|
||||
(
|
||||
"http://example/timeshift/myuser/mypass/3/2026-06-17:14-00/449.ts",
|
||||
"http://***/timeshift/***/3/2026-06-17:14-00/449.ts",
|
||||
),
|
||||
("http://example/streaming/myuser/mypass/123.ts", "http://***/streaming/***/123.ts"),
|
||||
("http://example/xtream/myuser/mypass/123.ts", "http://***/xtream/***/123.ts"),
|
||||
("http://example/timeshift.php/myuser/mypass/123.ts", "http://***/timeshift.php/***/123.ts"),
|
||||
("https://provider.example/movie/myuser/mypass/456.ts", "https://***/movie/***/456.ts"),
|
||||
("https://provider.example/series/myuser/mypass/789.ts", "https://***/series/***/789.ts"),
|
||||
];
|
||||
|
||||
for (input, expected) in cases {
|
||||
assert_eq!(sanitize_sensitive_info(input).as_ref(), *expected, "input: {input}");
|
||||
}
|
||||
|
||||
// Query-string credentials are masked by `re_credentials`, not by the
|
||||
// stream-URL rewriter — the host is still masked by `re_url`.
|
||||
assert_eq!(
|
||||
sanitize_sensitive_info("http://example/player_api.php?username=foo&password=bar"),
|
||||
"http://***/player_api.php?username=***&password=***"
|
||||
);
|
||||
|
||||
set_sanitize_sensitive_info(previous);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user