Initial commit — ferrosonic terminal Subsonic client

Terminal-based Subsonic music client in Rust featuring bit-perfect audio
playback via PipeWire sample rate switching, gapless playback, MPRIS2
desktop integration, cava audio visualizer with theme-matched gradients,
13 built-in color themes with custom TOML theme support, mouse controls,
artist/album browser, playlist support, and play queue management.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
2026-01-27 21:43:26 +00:00
commit 12cc70e6ec
36 changed files with 11600 additions and 0 deletions

61
src/subsonic/auth.rs Normal file
View File

@@ -0,0 +1,61 @@
//! Subsonic authentication helpers
use rand::Rng;
/// Generate authentication parameters for Subsonic API requests
///
/// Subsonic uses token-based authentication:
/// - salt: random string
/// - token: md5(password + salt)
pub fn generate_auth_params(password: &str) -> (String, String) {
let salt = generate_salt();
let token = generate_token(password, &salt);
(salt, token)
}
/// Generate a random salt string
fn generate_salt() -> String {
let mut rng = rand::thread_rng();
(0..16)
.map(|_| {
let idx = rng.gen_range(0..36);
if idx < 10 {
(b'0' + idx) as char
} else {
(b'a' + idx - 10) as char
}
})
.collect()
}
/// Generate authentication token: md5(password + salt)
fn generate_token(password: &str, salt: &str) -> String {
let input = format!("{}{}", password, salt);
let digest = md5::compute(input.as_bytes());
format!("{:x}", digest)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_generate_token() {
// Test with known values
let token = generate_token("sesame", "c19b2d");
assert_eq!(token, "26719a1196d2a940705a59634eb18eab");
}
#[test]
fn test_generate_salt_length() {
let salt = generate_salt();
assert_eq!(salt.len(), 16);
}
#[test]
fn test_auth_params() {
let (salt, token) = generate_auth_params("password");
assert_eq!(salt.len(), 16);
assert_eq!(token.len(), 32); // MD5 hex is 32 chars
}
}