Removed the dependency on OpenSSL on Windows
- Replaced session handling by secure_session - Required updating a bunch of dependencies - Replaced Hyper Client usage in DDNS by Reqwest (which only uses OpenSSL on Linux)
This commit is contained in:
parent
425e1f4ad8
commit
86e618d2a5
5 changed files with 720 additions and 419 deletions
968
Cargo.lock
generated
968
Cargo.lock
generated
File diff suppressed because it is too large
Load diff
22
Cargo.toml
22
Cargo.toml
|
@ -11,24 +11,26 @@ ape = "0.1.2"
|
|||
app_dirs = { git = "https://github.com/agersant/app-dirs-rs" }
|
||||
error-chain = "0.7.1"
|
||||
getopts = "0.2.14"
|
||||
hyper = "0.9.10"
|
||||
hyper = "0.10.0"
|
||||
id3 = "0.1.11"
|
||||
image = "0.10.3"
|
||||
iron = "0.4.0"
|
||||
iron = "0.5.1"
|
||||
lewton = "0.4.1"
|
||||
metaflac = "0.1.4"
|
||||
mount = "0.2.1"
|
||||
mount = "0.3.0"
|
||||
ogg = "0.4.0"
|
||||
oven = { git = "https://github.com/agersant/oven", branch = "remove_cookie_dep" }
|
||||
params = "0.5.1"
|
||||
params = "*"
|
||||
regex = "0.1"
|
||||
reqwest = "0.6.2"
|
||||
router = "0.4.0"
|
||||
serde = "1.0.2"
|
||||
serde_derive = "1.0.2"
|
||||
serde_json = "1.0.2"
|
||||
secure-session = "0.1.0"
|
||||
serde = "0.9"
|
||||
serde_derive = "0.9"
|
||||
serde_json = "0.9"
|
||||
sqlite = "0.23.0"
|
||||
staticfile = "0.3.0"
|
||||
toml = "0.4"
|
||||
staticfile = "0.4.0"
|
||||
toml = "=0.3.2"
|
||||
typemap = "0.3"
|
||||
url = "1.2.0"
|
||||
|
||||
[target.'cfg(windows)'.dependencies]
|
||||
|
|
71
src/api.rs
71
src/api.rs
|
@ -5,12 +5,14 @@ use std::ops::Deref;
|
|||
use std::sync::Arc;
|
||||
|
||||
use iron::prelude::*;
|
||||
use iron::headers::{Authorization, Basic, CookiePair};
|
||||
use iron::headers::{Authorization, Basic, SetCookie};
|
||||
use iron::{AroundMiddleware, Handler, status};
|
||||
use mount::Mount;
|
||||
use oven::prelude::*;
|
||||
use params;
|
||||
use secure_session::middleware::{SessionMiddleware, SessionConfig};
|
||||
use secure_session::session::{SessionManager, ChaCha20Poly1305SessionManager};
|
||||
use serde_json;
|
||||
use typemap;
|
||||
use url::percent_encoding::percent_decode;
|
||||
|
||||
use collection::*;
|
||||
|
@ -36,7 +38,31 @@ impl Version {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn get_api_handler(collection: Arc<Collection>) -> Mount {
|
||||
#[derive(Deserialize, Serialize)]
|
||||
struct Session {
|
||||
username: String,
|
||||
}
|
||||
|
||||
struct SessionKey {}
|
||||
|
||||
impl typemap::Key for SessionKey {
|
||||
type Value = Session;
|
||||
}
|
||||
|
||||
pub fn get_handler(collection: Collection, secret: &str) -> Chain {
|
||||
let collection = Arc::new(collection);
|
||||
let api_handler = get_endpoints(collection);
|
||||
let mut api_chain = Chain::new(api_handler);
|
||||
|
||||
let manager = ChaCha20Poly1305SessionManager::<Session>::from_password(secret.as_bytes());
|
||||
let config = SessionConfig::default();
|
||||
let session_middleware = SessionMiddleware::<Session, SessionKey, ChaCha20Poly1305SessionManager<Session>>::new(manager, config);
|
||||
api_chain.link_around(session_middleware);
|
||||
|
||||
api_chain
|
||||
}
|
||||
|
||||
fn get_endpoints(collection: Arc<Collection>) -> Mount {
|
||||
let mut api_handler = Mount::new();
|
||||
|
||||
{
|
||||
|
@ -116,9 +142,11 @@ struct AuthHandler {
|
|||
}
|
||||
|
||||
fn set_cookie(username: &str, response: &mut Response) {
|
||||
let mut username_cookie = CookiePair::new("username".to_string(), username.to_string());
|
||||
username_cookie.path = Some("/".to_owned());
|
||||
response.set_cookie(username_cookie);
|
||||
response.headers.set(
|
||||
SetCookie(vec![
|
||||
format!("username={}; Path=/", username)
|
||||
])
|
||||
);
|
||||
}
|
||||
|
||||
impl Handler for AuthHandler {
|
||||
|
@ -133,18 +161,20 @@ impl Handler for AuthHandler {
|
|||
auth_success = self.collection
|
||||
.auth(auth.username.as_str(), password.as_str());
|
||||
username = Some(auth.username.clone());
|
||||
req.extensions.insert::<SessionKey>(Session { username: auth.username.clone() });
|
||||
}
|
||||
}
|
||||
|
||||
// Auth via Cookie
|
||||
// Auth via Session
|
||||
if !auth_success {
|
||||
auth_success = req.get_cookie("username").is_some();
|
||||
auth_success = req.extensions.get::<SessionKey>().is_some();
|
||||
}
|
||||
|
||||
// Reject
|
||||
if !auth_success {
|
||||
return Err(Error::from(ErrorKind::AuthenticationRequired).into());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
let mut response = self.handler.handle(req);
|
||||
|
@ -169,18 +199,23 @@ fn version(_: &mut Request) -> IronResult<Response> {
|
|||
}
|
||||
|
||||
fn auth(request: &mut Request, collection: &Collection) -> IronResult<Response> {
|
||||
let input = request.get_ref::<params::Params>().unwrap();
|
||||
let username = match input.find(&["username"]) {
|
||||
Some(¶ms::Value::String(ref username)) => username,
|
||||
_ => return Err(Error::from(ErrorKind::MissingUsername).into()),
|
||||
};
|
||||
let password = match input.find(&["password"]) {
|
||||
Some(¶ms::Value::String(ref password)) => password,
|
||||
_ => return Err(Error::from(ErrorKind::MissingPassword).into()),
|
||||
};
|
||||
let username;
|
||||
let password;
|
||||
{
|
||||
let input = request.get_ref::<params::Params>().unwrap();
|
||||
username = match input.find(&["username"]) {
|
||||
Some(¶ms::Value::String(ref username)) => username.clone(),
|
||||
_ => return Err(Error::from(ErrorKind::MissingUsername).into()),
|
||||
};
|
||||
password = match input.find(&["password"]) {
|
||||
Some(¶ms::Value::String(ref password)) => password.clone(),
|
||||
_ => return Err(Error::from(ErrorKind::MissingPassword).into()),
|
||||
};
|
||||
}
|
||||
if collection.auth(username.as_str(), password.as_str()) {
|
||||
let mut response = Response::with((status::Ok, ""));
|
||||
set_cookie(username.as_str(), &mut response);
|
||||
set_cookie(&username, &mut response);
|
||||
request.extensions.insert::<SessionKey>(Session { username: username.clone() });
|
||||
Ok(response)
|
||||
} else {
|
||||
Err(Error::from(ErrorKind::IncorrectCredentials).into())
|
||||
|
|
54
src/ddns.rs
54
src/ddns.rs
|
@ -1,8 +1,6 @@
|
|||
use hyper;
|
||||
use hyper::client::Client;
|
||||
use hyper::header::{Authorization, Basic};
|
||||
use reqwest;
|
||||
use reqwest::header::{Authorization, Basic};
|
||||
use std::io;
|
||||
use std::io::Read;
|
||||
use std::thread;
|
||||
use std::time;
|
||||
|
||||
|
@ -16,8 +14,8 @@ pub struct DDNSConfig {
|
|||
#[derive(Debug)]
|
||||
enum DDNSError {
|
||||
IoError(io::Error),
|
||||
HyperError(hyper::Error),
|
||||
UpdateError(hyper::status::StatusCode),
|
||||
ReqwestError(reqwest::Error),
|
||||
UpdateError(reqwest::StatusCode),
|
||||
}
|
||||
|
||||
impl From<io::Error> for DDNSError {
|
||||
|
@ -26,54 +24,38 @@ impl From<io::Error> for DDNSError {
|
|||
}
|
||||
}
|
||||
|
||||
impl From<hyper::Error> for DDNSError {
|
||||
fn from(err: hyper::Error) -> DDNSError {
|
||||
DDNSError::HyperError(err)
|
||||
impl From<reqwest::Error> for DDNSError {
|
||||
fn from(err: reqwest::Error) -> DDNSError {
|
||||
DDNSError::ReqwestError(err)
|
||||
}
|
||||
}
|
||||
|
||||
const MY_IP_API_URL: &'static str = "http://api.ipify.org";
|
||||
const DDNS_UPDATE_URL: &'static str = "http://ydns.io/api/v1/update/";
|
||||
const DDNS_UPDATE_URL: &'static str = "https://ydns.io/api/v1/update/";
|
||||
|
||||
fn get_my_ip() -> Result<String, DDNSError> {
|
||||
let client = Client::new();
|
||||
let mut res = client.get(MY_IP_API_URL).send()?;
|
||||
let mut buf = String::new();
|
||||
res.read_to_string(&mut buf)?;
|
||||
Ok(buf)
|
||||
}
|
||||
|
||||
fn update_my_ip(ip: &String, config: &DDNSConfig) -> Result<(), DDNSError> {
|
||||
let client = Client::new();
|
||||
let url = DDNS_UPDATE_URL;
|
||||
let host = &config.host;
|
||||
let full_url = format!("{}?host={}&ip={}", url, host, ip);
|
||||
fn update_my_ip(config: &DDNSConfig) -> Result<(), DDNSError> {
|
||||
let full_url = format!("{}?host={}", DDNS_UPDATE_URL, &config.host);
|
||||
let auth_header = Authorization(Basic {
|
||||
username: config.username.clone(),
|
||||
password: Some(config.password.to_owned()),
|
||||
});
|
||||
|
||||
let client = reqwest::Client::new()?;
|
||||
let res = client
|
||||
.get(full_url.as_str())
|
||||
.header(auth_header)
|
||||
.send()?;
|
||||
match res.status {
|
||||
hyper::status::StatusCode::Ok => Ok(()),
|
||||
s => Err(DDNSError::UpdateError(s)),
|
||||
if !res.status().is_success() {
|
||||
return Err(DDNSError::UpdateError(*res.status()));
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn run(config: DDNSConfig) {
|
||||
loop {
|
||||
let my_ip_res = get_my_ip();
|
||||
if let Ok(my_ip) = my_ip_res {
|
||||
match update_my_ip(&my_ip, &config) {
|
||||
Err(e) => println!("Dynamic DNS Error: {:?}", e),
|
||||
Ok(_) => (),
|
||||
};
|
||||
} else {
|
||||
println!("Dynamic DNS Error: could not retrieve our own IP address");
|
||||
}
|
||||
match update_my_ip(&config) {
|
||||
Err(e) => println!("Dynamic DNS Error: {:?}", e),
|
||||
Ok(_) => (),
|
||||
};
|
||||
thread::sleep(time::Duration::from_secs(60 * 30));
|
||||
}
|
||||
}
|
||||
|
|
24
src/main.rs
24
src/main.rs
|
@ -14,9 +14,10 @@ extern crate lewton;
|
|||
extern crate metaflac;
|
||||
extern crate mount;
|
||||
extern crate ogg;
|
||||
extern crate oven;
|
||||
extern crate params;
|
||||
extern crate reqwest;
|
||||
extern crate regex;
|
||||
extern crate secure_session;
|
||||
extern crate serde;
|
||||
#[macro_use]
|
||||
extern crate serde_derive;
|
||||
|
@ -24,6 +25,7 @@ extern crate serde_json;
|
|||
extern crate staticfile;
|
||||
extern crate sqlite;
|
||||
extern crate toml;
|
||||
extern crate typemap;
|
||||
extern crate url;
|
||||
|
||||
#[cfg(windows)]
|
||||
|
@ -116,22 +118,10 @@ fn run() -> Result<()> {
|
|||
// Mount API
|
||||
println!("Mounting API");
|
||||
let mut mount = Mount::new();
|
||||
let mut api_chain;
|
||||
{
|
||||
let api_handler;
|
||||
{
|
||||
let mut collection = collection::Collection::new(vfs, index);
|
||||
collection.load_config(&config)?;
|
||||
let collection = Arc::new(collection);
|
||||
api_handler = api::get_api_handler(collection);
|
||||
}
|
||||
api_chain = Chain::new(api_handler);
|
||||
|
||||
let auth_secret = config.secret.to_owned();
|
||||
let cookie_middleware = oven::new(auth_secret.into_bytes());
|
||||
api_chain.link(cookie_middleware);
|
||||
}
|
||||
mount.mount("/api/", api_chain);
|
||||
let mut collection = collection::Collection::new(vfs, index);
|
||||
collection.load_config(&config)?;
|
||||
let handler = api::get_handler(collection, &config.secret);
|
||||
mount.mount("/api/", handler);
|
||||
|
||||
// Mount static files
|
||||
println!("Mounting static files");
|
||||
|
|
Loading…
Add table
Reference in a new issue