diff options
Diffstat (limited to 'import/asset_token/src/lib.rs')
| -rw-r--r-- | import/asset_token/src/lib.rs | 111 |
1 files changed, 0 insertions, 111 deletions
diff --git a/import/asset_token/src/lib.rs b/import/asset_token/src/lib.rs deleted file mode 100644 index ef1850e..0000000 --- a/import/asset_token/src/lib.rs +++ /dev/null @@ -1,111 +0,0 @@ -/* - This file is part of jellything (https://codeberg.org/metamuffin/jellything) - which is licensed under the GNU Affero General Public License (version 3); see /COPYING. - Copyright (C) 2025 metamuffin <metamuffin.org> -*/ -use aes_gcm_siv::{aead::Aead, Aes256GcmSiv, KeyInit}; -use anyhow::{anyhow, bail, Context}; -use base64::Engine; -use jellycache::CachePath; -pub use jellycommon as common; -use jellycommon::{Asset, LocalTrack}; -use log::warn; -use serde::{Deserialize, Serialize}; -use sha2::digest::generic_array::GenericArray; -use std::sync::Mutex; -use std::{path::PathBuf, sync::LazyLock}; - -#[rustfmt::skip] -#[derive(Debug, Deserialize, Serialize, Default)] -pub struct Config { - asset_key: Option<String>, -} - -pub static CONF_PRELOAD: Mutex<Option<Config>> = Mutex::new(None); -static CONF: LazyLock<Config> = LazyLock::new(|| { - CONF_PRELOAD - .lock() - .unwrap() - .take() - .expect("cache config not preloaded. logic error") -}); - -const VERSION: u32 = 3; - -static ASSET_KEY: LazyLock<Aes256GcmSiv> = LazyLock::new(|| { - if let Some(sk) = &CONF.asset_key { - let r = base64::engine::general_purpose::STANDARD - .decode(sk) - .expect("key invalid; should be valid base64"); - aes_gcm_siv::Aes256GcmSiv::new_from_slice(&r) - .expect("key has the wrong length; should be 32 bytes") - } else { - warn!("session_key not configured; generating a random one."); - aes_gcm_siv::Aes256GcmSiv::new_from_slice(&[(); 32].map(|_| rand::random())).unwrap() - } -}); - -#[derive(Debug, Serialize, PartialEq, Eq)] -pub enum AssetInner { - Federated { host: String, asset: Vec<u8> }, - Cache(CachePath), - Assets(PathBuf), - Media(PathBuf), - LocalTrack(LocalTrack), -} - -impl AssetInner { - pub fn ser(&self) -> Asset { - let mut plaintext = Vec::new(); - plaintext.extend(u32::to_le_bytes(VERSION)); - plaintext.extend(bincode::encode_to_vec(self, bincode::config::standard()).unwrap()); - - while plaintext.len() % 16 == 0 { - plaintext.push(0); - } - - let nonce = [(); 12].map(|_| rand::random()); - let mut ciphertext = ASSET_KEY - .encrypt(&GenericArray::from(nonce), plaintext.as_slice()) - .unwrap(); - ciphertext.extend(nonce); - - Asset(base64::engine::general_purpose::URL_SAFE.encode(&ciphertext)) - } - pub fn deser(s: &str) -> anyhow::Result<Self> { - let ciphertext = base64::engine::general_purpose::URL_SAFE.decode(s)?; - let (ciphertext, nonce) = ciphertext.split_at(ciphertext.len() - 12); - let plaintext = ASSET_KEY - .decrypt(nonce.into(), ciphertext) - .map_err(|_| anyhow!("asset token decrypt failed"))?; - - let version = u32::from_le_bytes(plaintext[0..4].try_into().unwrap()); - if version != VERSION { - bail!("asset token version mismatch"); - } - - let (data, _): (AssetInner, _) = - bincode::decode_from_slice(&plaintext[4..], bincode::config::standard()) - .context("asset token has invalid format")?; - Ok(data) - } - - /// Returns `true` if the asset inner is [`Federated`]. - /// - /// [`Federated`]: AssetInner::Federated - #[must_use] - pub fn is_federated(&self) -> bool { - matches!(self, Self::Federated { .. }) - } -} - -#[test] -fn test_identities() { - *CONF_PRELOAD.lock().unwrap() = Some(Config { asset_key: None }); - - let a = AssetInner::Assets(PathBuf::new()); - let b = a.ser(); - let c = AssetInner::deser(&b.0).unwrap(); - - assert_eq!(a, c) -} |