diff options
author | metamuffin <metamuffin@disroot.org> | 2023-10-04 23:32:24 +0200 |
---|---|---|
committer | metamuffin <metamuffin@disroot.org> | 2023-10-04 23:32:24 +0200 |
commit | 95e43ac88a322251a5e5a7d529b7b20a511978fd (patch) | |
tree | 52e86d7917b7de9c3c2e38fdd580a621c2726961 | |
parent | ae6885187b0aa881164151ab97bd4887c83b775a (diff) | |
download | jellything-95e43ac88a322251a5e5a7d529b7b20a511978fd.tar jellything-95e43ac88a322251a5e5a7d529b7b20a511978fd.tar.bz2 jellything-95e43ac88a322251a5e5a7d529b7b20a511978fd.tar.zst |
more permissions
-rw-r--r-- | common/src/stream.rs | 2 | ||||
-rw-r--r-- | common/src/user.rs | 21 | ||||
-rw-r--r-- | server/src/routes/stream.rs | 14 | ||||
-rw-r--r-- | stream/src/jhls.rs | 10 | ||||
-rw-r--r-- | stream/src/lib.rs | 16 | ||||
-rw-r--r-- | stream/src/segment.rs | 10 |
6 files changed, 57 insertions, 16 deletions
diff --git a/common/src/stream.rs b/common/src/stream.rs index 8a7ff36..6c93294 100644 --- a/common/src/stream.rs +++ b/common/src/stream.rs @@ -18,7 +18,7 @@ pub struct StreamSpec { } #[rustfmt::skip] -#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, Eq)] +#[derive(Debug, Clone, Copy, Deserialize, Serialize, PartialEq, Eq, Hash)] #[serde(rename_all = "snake_case")] #[cfg_attr(feature = "rocket", derive(FromFormField, UriDisplayQuery))] pub enum StreamFormat { diff --git a/common/src/user.rs b/common/src/user.rs index b049346..3c1c5b0 100644 --- a/common/src/user.rs +++ b/common/src/user.rs @@ -1,3 +1,4 @@ +use crate::{stream::StreamFormat, user}; use serde::{Deserialize, Serialize}; use std::{collections::HashMap, fmt::Display}; @@ -17,22 +18,26 @@ pub struct PermissionSet(pub HashMap<UserPermission, bool>); #[serde(rename_all = "snake_case")] pub enum UserPermission { Admin, - OriginalStream, Transcode, ManageUsers, FederatedContent, GenerateInvite, + StreamFormat(StreamFormat), AccessNode(String), } impl UserPermission { pub const ALL_ENUMERABLE: &'static [UserPermission] = { use UserPermission::*; - &[Admin, OriginalStream, Transcode] + &[Admin, Transcode, StreamFormat(user::StreamFormat::Original)] }; pub fn default_value(&self) -> bool { + use user::StreamFormat::*; use UserPermission::*; - matches!(self, Transcode) + matches!( + self, + Transcode | StreamFormat(Jhls | HlsMaster | HlsVariant | Matroska | Segment) + ) } } @@ -41,7 +46,15 @@ impl Display for UserPermission { f.write_str(&match self { UserPermission::FederatedContent => format!("access to federated content"), UserPermission::Admin => format!("administrative rights"), - UserPermission::OriginalStream => format!("download of the original media"), + UserPermission::StreamFormat(StreamFormat::Original) => { + format!("downloading the original media") + } + UserPermission::StreamFormat(StreamFormat::Matroska) => { + format!("downloading a remuxed WebM/Matroska version of the media ") + } + UserPermission::StreamFormat(x) => { + format!("downloading media via {x:?}") + } UserPermission::Transcode => format!("transcoding"), UserPermission::ManageUsers => format!("management of all users"), UserPermission::GenerateInvite => format!("inviting new users"), diff --git a/server/src/routes/stream.rs b/server/src/routes/stream.rs index b1248ba..0569903 100644 --- a/server/src/routes/stream.rs +++ b/server/src/routes/stream.rs @@ -6,8 +6,11 @@ use super::ui::{account::session::Session, error::MyError}; use crate::{database::Database, federation::Federation}; use anyhow::{anyhow, Result}; -use jellybase::{permission::NodePermissionExt, CONF}; -use jellycommon::{stream::StreamSpec, MediaSource}; +use jellybase::{ + permission::{NodePermissionExt, PermissionSetExt}, + CONF, +}; +use jellycommon::{stream::StreamSpec, user::UserPermission, MediaSource}; use log::{info, warn}; use rocket::{ get, head, @@ -55,6 +58,11 @@ pub async fn r_stream( .ok_or(anyhow!("item does not contain media"))?; if let MediaSource::Remote { host, remote_id } = source { + session + .user + .permissions + .assert(&UserPermission::FederatedContent)?; + let (username, password, _) = CONF .remote_credentials .get(host) @@ -91,7 +99,7 @@ pub async fn r_stream( let head = jellystream::stream_head(&spec); - match jellystream::stream(node, spec, urange).await { + match jellystream::stream(node, spec, urange, &session.user.permissions).await { Ok(stream) => Ok(Either::Left(StreamResponse { stream, range, diff --git a/stream/src/jhls.rs b/stream/src/jhls.rs index 5183a26..850cc32 100644 --- a/stream/src/jhls.rs +++ b/stream/src/jhls.rs @@ -1,8 +1,9 @@ use anyhow::Result; -use jellybase::CONF; +use jellybase::{permission::PermissionSetExt, CONF}; use jellycommon::{ jhls::{JhlsMetadata, JhlsTrack}, stream::StreamSpec, + user::{PermissionSet, UserPermission}, LocalTrack, Node, }; use tokio::io::{AsyncWriteExt, DuplexStream}; @@ -12,6 +13,7 @@ pub async fn jhls_stream( track_sources: Vec<LocalTrack>, _spec: StreamSpec, mut b: DuplexStream, + perms: &PermissionSet, ) -> Result<()> { let media = node.public.media.clone().unwrap(); let tracks = tokio::task::spawn_blocking(move || { @@ -42,7 +44,11 @@ pub async fn jhls_stream( let out = serde_json::to_string(&JhlsMetadata { tracks, - extra_profiles: CONF.transcoding_profiles.clone(), + extra_profiles: if perms.check(&UserPermission::Transcode) { + CONF.transcoding_profiles.clone() + } else { + vec![] + }, duration: media.duration, })?; tokio::spawn(async move { b.write_all(out.as_bytes()).await }); diff --git a/stream/src/lib.rs b/stream/src/lib.rs index 85ff382..e9b9a4b 100644 --- a/stream/src/lib.rs +++ b/stream/src/lib.rs @@ -10,9 +10,10 @@ pub mod segment; use anyhow::{anyhow, bail, Context, Result}; use hls::{hls_master_stream, hls_variant_stream}; -use jellybase::CONF; +use jellybase::{permission::PermissionSetExt, CONF}; use jellycommon::{ stream::{StreamFormat, StreamSpec}, + user::{PermissionSet, UserPermission}, LocalTrack, MediaSource, Node, }; use jhls::jhls_stream; @@ -41,7 +42,14 @@ pub fn stream_head(spec: &StreamSpec) -> StreamHead { } } -pub async fn stream(node: Node, spec: StreamSpec, range: Range<usize>) -> Result<DuplexStream> { +pub async fn stream( + node: Node, + spec: StreamSpec, + range: Range<usize>, + perms: &PermissionSet, +) -> Result<DuplexStream> { + perms.assert(&UserPermission::StreamFormat(spec.format))?; + let (a, b) = duplex(4096); let track_sources = match node @@ -59,8 +67,8 @@ pub async fn stream(node: Node, spec: StreamSpec, range: Range<usize>) -> Result StreamFormat::Matroska => remux_stream(node, track_sources, spec, range, b).await?, StreamFormat::HlsMaster => hls_master_stream(node, track_sources, spec, b).await?, StreamFormat::HlsVariant => hls_variant_stream(node, track_sources, spec, b).await?, - StreamFormat::Jhls => jhls_stream(node, track_sources, spec, b).await?, - StreamFormat::Segment => segment_stream(node, track_sources, spec, b).await?, + StreamFormat::Jhls => jhls_stream(node, track_sources, spec, b, perms).await?, + StreamFormat::Segment => segment_stream(node, track_sources, spec, b, perms).await?, } Ok(a) diff --git a/stream/src/segment.rs b/stream/src/segment.rs index ce3f8e1..309da1d 100644 --- a/stream/src/segment.rs +++ b/stream/src/segment.rs @@ -4,8 +4,12 @@ Copyright (C) 2023 metamuffin <metamuffin.org> */ use anyhow::{anyhow, bail, Result}; -use jellybase::{AssetLocationExt, CONF}; -use jellycommon::{stream::StreamSpec, LocalTrack, Node}; +use jellybase::{permission::PermissionSetExt, AssetLocationExt, CONF}; +use jellycommon::{ + stream::StreamSpec, + user::{PermissionSet, UserPermission}, + LocalTrack, Node, +}; use jellytranscoder::snippet::transcode; use log::warn; use tokio::{fs::File, io::DuplexStream}; @@ -16,6 +20,7 @@ pub async fn segment_stream( track_sources: Vec<LocalTrack>, spec: StreamSpec, mut b: DuplexStream, + perms: &PermissionSet, ) -> Result<()> { if spec.tracks.len() != 1 { bail!("unsupported number of tracks for segment, must be exactly one"); @@ -24,6 +29,7 @@ pub async fn segment_stream( let n = spec.index.ok_or(anyhow!("segment index missing"))?; if let Some(profile) = spec.profile { + perms.assert(&UserPermission::Transcode)?; let location = transcode( &format!("{track} {n} {:?}", node.private.source), // TODO maybe not use the entire source CONF.transcoding_profiles |