Added API endpoint to unlink last.fm account
This commit is contained in:
parent
a84f13214d
commit
f905bc4f73
8 changed files with 172 additions and 103 deletions
74
src/api.rs
74
src/api.rs
|
@ -1,4 +1,5 @@
|
||||||
use base64;
|
use base64;
|
||||||
|
use crypto::scrypt;
|
||||||
use diesel::prelude::*;
|
use diesel::prelude::*;
|
||||||
use iron::headers::{Authorization, Basic, Range};
|
use iron::headers::{Authorization, Basic, Range};
|
||||||
use iron::mime::Mime;
|
use iron::mime::Mime;
|
||||||
|
@ -7,7 +8,6 @@ use iron::{status, AroundMiddleware, Handler};
|
||||||
use mount::Mount;
|
use mount::Mount;
|
||||||
use params;
|
use params;
|
||||||
use router::Router;
|
use router::Router;
|
||||||
use crypto::scrypt;
|
|
||||||
use secure_session::middleware::{SessionConfig, SessionMiddleware};
|
use secure_session::middleware::{SessionConfig, SessionMiddleware};
|
||||||
use secure_session::session::ChaCha20Poly1305SessionManager;
|
use secure_session::session::ChaCha20Poly1305SessionManager;
|
||||||
use serde_json;
|
use serde_json;
|
||||||
|
@ -57,7 +57,12 @@ where
|
||||||
|
|
||||||
let params = scrypt::ScryptParams::new(12, 8, 1);
|
let params = scrypt::ScryptParams::new(12, 8, 1);
|
||||||
let mut secret = [0; 32];
|
let mut secret = [0; 32];
|
||||||
scrypt::scrypt(misc.auth_secret.as_bytes(), b"polaris-salt-and-pepper-with-cheese", ¶ms, &mut secret);
|
scrypt::scrypt(
|
||||||
|
misc.auth_secret.as_bytes(),
|
||||||
|
b"polaris-salt-and-pepper-with-cheese",
|
||||||
|
¶ms,
|
||||||
|
&mut secret,
|
||||||
|
);
|
||||||
Ok(secret)
|
Ok(secret)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -66,8 +71,7 @@ pub fn get_handler(db: &Arc<DB>, index: &Arc<Mutex<Sender<index::Command>>>) ->
|
||||||
let mut api_chain = Chain::new(api_handler);
|
let mut api_chain = Chain::new(api_handler);
|
||||||
|
|
||||||
let auth_secret = get_auth_secret(db.deref())?;
|
let auth_secret = get_auth_secret(db.deref())?;
|
||||||
let session_manager =
|
let session_manager = ChaCha20Poly1305SessionManager::<Session>::from_key(auth_secret);
|
||||||
ChaCha20Poly1305SessionManager::<Session>::from_key(auth_secret);
|
|
||||||
let session_config = SessionConfig::default();
|
let session_config = SessionConfig::default();
|
||||||
let session_middleware = SessionMiddleware::<
|
let session_middleware = SessionMiddleware::<
|
||||||
Session,
|
Session,
|
||||||
|
@ -221,22 +225,39 @@ fn get_endpoints(db: &Arc<DB>, index_channel: &Arc<Mutex<Sender<index::Command>>
|
||||||
auth_api_mount.mount("/playlist/", playlist_router);
|
auth_api_mount.mount("/playlist/", playlist_router);
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
let db = db.clone();
|
let mut lastfm_router = Router::new();
|
||||||
auth_api_mount.mount("/lastfm/auth/", move |request: &mut Request| {
|
let now_playing_db = db.clone();
|
||||||
self::lastfm_auth(request, db.deref())
|
let link_db = db.clone();
|
||||||
});
|
let unlink_db = db.clone();
|
||||||
}
|
let scrobble_db = db.clone();
|
||||||
{
|
|
||||||
let db = db.clone();
|
lastfm_router.put(
|
||||||
auth_api_mount.mount("/lastfm/now_playing/", move |request: &mut Request| {
|
"/now_playing",
|
||||||
self::lastfm_now_playing(request, db.deref())
|
move |request: &mut Request| {
|
||||||
});
|
self::lastfm_now_playing(request, now_playing_db.deref())
|
||||||
}
|
},
|
||||||
{
|
"now_playing",
|
||||||
let db = db.clone();
|
);
|
||||||
auth_api_mount.mount("/lastfm/scrobble/", move |request: &mut Request| {
|
|
||||||
self::lastfm_scrobble(request, db.deref())
|
lastfm_router.get(
|
||||||
});
|
"/link",
|
||||||
|
move |request: &mut Request| self::lastfm_link(request, link_db.deref()),
|
||||||
|
"link",
|
||||||
|
);
|
||||||
|
|
||||||
|
lastfm_router.delete(
|
||||||
|
"/link",
|
||||||
|
move |request: &mut Request| self::lastfm_unlink(request, unlink_db.deref()),
|
||||||
|
"unlink",
|
||||||
|
);
|
||||||
|
|
||||||
|
lastfm_router.get(
|
||||||
|
"/scrobble",
|
||||||
|
move |request: &mut Request| self::lastfm_scrobble(request, scrobble_db.deref()),
|
||||||
|
"auth",
|
||||||
|
);
|
||||||
|
|
||||||
|
auth_api_mount.mount("/lastfm/", lastfm_router);
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut auth_api_chain = Chain::new(auth_api_mount);
|
let mut auth_api_chain = Chain::new(auth_api_mount);
|
||||||
|
@ -715,7 +736,7 @@ fn delete_playlist(request: &mut Request, db: &DB) -> IronResult<Response> {
|
||||||
Ok(Response::with(status::Ok))
|
Ok(Response::with(status::Ok))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn lastfm_auth(request: &mut Request, db: &DB) -> IronResult<Response> {
|
fn lastfm_link(request: &mut Request, db: &DB) -> IronResult<Response> {
|
||||||
let input = request.get_ref::<params::Params>().unwrap();
|
let input = request.get_ref::<params::Params>().unwrap();
|
||||||
let username = match input.find(&["username"]) {
|
let username = match input.find(&["username"]) {
|
||||||
Some(¶ms::Value::String(ref username)) => username.clone(),
|
Some(¶ms::Value::String(ref username)) => username.clone(),
|
||||||
|
@ -726,7 +747,7 @@ fn lastfm_auth(request: &mut Request, db: &DB) -> IronResult<Response> {
|
||||||
_ => return Err(Error::from(ErrorKind::MissingPassword).into()),
|
_ => return Err(Error::from(ErrorKind::MissingPassword).into()),
|
||||||
};
|
};
|
||||||
|
|
||||||
lastfm::auth(db, &username, &token)?;
|
lastfm::link(db, &username, &token)?;
|
||||||
|
|
||||||
let url_encoded_content = match input.find(&["content"]) {
|
let url_encoded_content = match input.find(&["content"]) {
|
||||||
Some(¶ms::Value::String(ref content)) => content.clone(),
|
Some(¶ms::Value::String(ref content)) => content.clone(),
|
||||||
|
@ -748,6 +769,15 @@ fn lastfm_auth(request: &mut Request, db: &DB) -> IronResult<Response> {
|
||||||
Ok(Response::with((mime, status::Ok, popup_content)))
|
Ok(Response::with((mime, status::Ok, popup_content)))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn lastfm_unlink(request: &mut Request, db: &DB) -> IronResult<Response> {
|
||||||
|
let username = match request.extensions.get::<SessionKey>() {
|
||||||
|
Some(s) => s.username.clone(),
|
||||||
|
None => return Err(Error::from(ErrorKind::AuthenticationRequired).into()),
|
||||||
|
};
|
||||||
|
lastfm::unlink(db, &username)?;
|
||||||
|
Ok(Response::with(status::Ok))
|
||||||
|
}
|
||||||
|
|
||||||
fn lastfm_now_playing(request: &mut Request, db: &DB) -> IronResult<Response> {
|
fn lastfm_now_playing(request: &mut Request, db: &DB) -> IronResult<Response> {
|
||||||
let username = match request.extensions.get::<SessionKey>() {
|
let username = match request.extensions.get::<SessionKey>() {
|
||||||
Some(s) => s.username.clone(),
|
Some(s) => s.username.clone(),
|
||||||
|
|
|
@ -26,7 +26,9 @@ pub struct MiscSettings {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
|
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
|
||||||
pub struct Preferences {}
|
pub struct Preferences {
|
||||||
|
pub lastfm_username: Option<String>,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
|
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
|
||||||
pub struct ConfigUser {
|
pub struct ConfigUser {
|
||||||
|
@ -252,11 +254,19 @@ where
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn read_preferences<T>(_: &T, _: &str) -> Result<Preferences>
|
pub fn read_preferences<T>(db: &T, username: &str) -> Result<Preferences>
|
||||||
where
|
where
|
||||||
T: ConnectionSource,
|
T: ConnectionSource,
|
||||||
{
|
{
|
||||||
Ok(Preferences {})
|
use self::users::dsl::*;
|
||||||
|
let connection = db.get_connection();
|
||||||
|
let read_lastfm_username = users
|
||||||
|
.select(lastfm_username)
|
||||||
|
.filter(name.eq(username))
|
||||||
|
.get_result(connection.deref())?;
|
||||||
|
Ok(Preferences {
|
||||||
|
lastfm_username: read_lastfm_username,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn write_preferences<T>(_: &T, _: &str, _: &Preferences) -> Result<()>
|
pub fn write_preferences<T>(_: &T, _: &str, _: &Preferences) -> Result<()>
|
||||||
|
|
|
@ -71,7 +71,10 @@ where
|
||||||
|
|
||||||
let full_url = format!("{}?host={}", DDNS_UPDATE_URL, &config.host);
|
let full_url = format!("{}?host={}", DDNS_UPDATE_URL, &config.host);
|
||||||
let client = reqwest::ClientBuilder::new().build()?;
|
let client = reqwest::ClientBuilder::new().build()?;
|
||||||
let res = client.get(full_url.as_str()).basic_auth(config.username, Some(config.password)).send()?;
|
let res = client
|
||||||
|
.get(full_url.as_str())
|
||||||
|
.basic_auth(config.username, Some(config.password))
|
||||||
|
.send()?;
|
||||||
if !res.status().is_success() {
|
if !res.status().is_success() {
|
||||||
return Err(DDNSError::Update(res.status()));
|
return Err(DDNSError::Update(res.status()));
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,8 +2,8 @@ use core::ops::Deref;
|
||||||
use diesel;
|
use diesel;
|
||||||
use diesel::dsl::sql;
|
use diesel::dsl::sql;
|
||||||
use diesel::prelude::*;
|
use diesel::prelude::*;
|
||||||
use diesel::sqlite::SqliteConnection;
|
|
||||||
use diesel::sql_types;
|
use diesel::sql_types;
|
||||||
|
use diesel::sqlite::SqliteConnection;
|
||||||
use regex::Regex;
|
use regex::Regex;
|
||||||
use std::fs;
|
use std::fs;
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
|
|
|
@ -59,7 +59,7 @@ where
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn auth<T>(db: &T, username: &str, token: &str) -> Result<(), errors::Error>
|
pub fn link<T>(db: &T, username: &str, token: &str) -> Result<(), errors::Error>
|
||||||
where
|
where
|
||||||
T: ConnectionSource + VFSSource,
|
T: ConnectionSource + VFSSource,
|
||||||
{
|
{
|
||||||
|
@ -82,7 +82,19 @@ where
|
||||||
Err(_) => bail!(errors::ErrorKind::LastFMDeserializationError),
|
Err(_) => bail!(errors::ErrorKind::LastFMDeserializationError),
|
||||||
};
|
};
|
||||||
|
|
||||||
user::set_lastfm_session_key(db, username, &auth_response.session.key.body)
|
user::lastfm_link(
|
||||||
|
db,
|
||||||
|
username,
|
||||||
|
&auth_response.session.name.body,
|
||||||
|
&auth_response.session.key.body,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn unlink<T>(db: &T, username: &str) -> Result<(), errors::Error>
|
||||||
|
where
|
||||||
|
T: ConnectionSource + VFSSource,
|
||||||
|
{
|
||||||
|
user::lastfm_unlink(db, username)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn scrobble<T>(db: &T, username: &str, track: &Path) -> Result<(), errors::Error>
|
pub fn scrobble<T>(db: &T, username: &str, track: &Path) -> Result<(), errors::Error>
|
||||||
|
|
|
@ -5,7 +5,7 @@ use image::GenericImageView;
|
||||||
use image::ImageBuffer;
|
use image::ImageBuffer;
|
||||||
use std::cmp;
|
use std::cmp;
|
||||||
use std::collections::hash_map::DefaultHasher;
|
use std::collections::hash_map::DefaultHasher;
|
||||||
use std::fs::{DirBuilder};
|
use std::fs::DirBuilder;
|
||||||
use std::hash::{Hash, Hasher};
|
use std::hash::{Hash, Hasher};
|
||||||
use std::path::*;
|
use std::path::*;
|
||||||
|
|
||||||
|
|
20
src/user.rs
20
src/user.rs
|
@ -101,15 +101,17 @@ where
|
||||||
Ok(is_admin != 0)
|
Ok(is_admin != 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_lastfm_session_key<T>(db: &T, username: &str, token: &str) -> Result<()>
|
pub fn lastfm_link<T>(db: &T, username: &str, lastfm_login: &str, session_key: &str) -> Result<()>
|
||||||
where
|
where
|
||||||
T: ConnectionSource,
|
T: ConnectionSource,
|
||||||
{
|
{
|
||||||
use db::users::dsl::*;
|
use db::users::dsl::*;
|
||||||
let connection = db.get_connection();
|
let connection = db.get_connection();
|
||||||
diesel::update(users.filter(name.eq(username)))
|
diesel::update(users.filter(name.eq(username)))
|
||||||
.set(lastfm_session_key.eq(token))
|
.set((
|
||||||
.execute(connection.deref())?;
|
lastfm_username.eq(lastfm_login),
|
||||||
|
lastfm_session_key.eq(session_key),
|
||||||
|
)).execute(connection.deref())?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -128,3 +130,15 @@ where
|
||||||
_ => bail!(ErrorKind::MissingLastFMCredentials),
|
_ => bail!(ErrorKind::MissingLastFMCredentials),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn lastfm_unlink<T>(db: &T, username: &str) -> Result<()>
|
||||||
|
where
|
||||||
|
T: ConnectionSource,
|
||||||
|
{
|
||||||
|
use db::users::dsl::*;
|
||||||
|
let connection = db.get_connection();
|
||||||
|
diesel::update(users.filter(name.eq(username)))
|
||||||
|
.set((lastfm_session_key.eq(""), lastfm_username.eq("")))
|
||||||
|
.execute(connection.deref())?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue