diff options
-rw-r--r-- | README.md | 33 | ||||
-rw-r--r-- | src/main.rs | 88 |
2 files changed, 84 insertions, 37 deletions
@@ -1,31 +1,30 @@ # Proxy -Proxy denying connections according to the given configuration. +Proxy denying connections depending on the time. ## Getting started -```bash -nix-shell --run "cargo-watch -x run -- --config config.dhall" -``` - -## Example configuration +Create `config.dhall`: ```dhall [ { - from = "00:00", - to = "23:59", - hosts = [ - "facebook.com", - "gstatic.com" - ] - }, - { - from = "19:00", - to = "17:00", + times = [ + { + days = "Monday-Sunday", + from = "00:00", + to = "23:59" + } + ], hosts = [ - "youtube.com" + "facebook.com" ] } ] ``` + +Then, run with: + +```bash +nix-shell --run 'cargo-watch -x "run -- --config config.dhall"' +``` diff --git a/src/main.rs b/src/main.rs index c1a79d0..ccfb81e 100644 --- a/src/main.rs +++ b/src/main.rs @@ -22,13 +22,22 @@ type HttpClient = Client<hyper::client::HttpConnector>; struct Opt { #[structopt(short, long)] config: String, + + #[structopt(short, long, default_value = "127.0.0.1:8200")] + address: SocketAddr, } #[derive(Debug, Deserialize, StaticType, Clone)] struct Access { + times: Vec<Time>, + hosts: Vec<String>, +} + +#[derive(Debug, Deserialize, StaticType, Clone)] +struct Time { + days: String, from: String, to: String, - hosts: Vec<String>, } #[tokio::main] @@ -42,7 +51,6 @@ async fn main() { .parse::<Vec<Access>>() { Ok(config) => { - let addr = SocketAddr::from(([127, 0, 0, 1], 8100)); let client = HttpClient::new(); let make_service = make_service_fn(move |_| { @@ -55,9 +63,9 @@ async fn main() { } }); - let server = Server::bind(&addr).serve(make_service); + let server = Server::bind(&opt.address).serve(make_service); - info!("Listening on http://{}", addr); + info!("Listening on http://{}", opt.address); if let Err(e) = server.await { error!("server error: {}", e); @@ -156,6 +164,8 @@ fn block_uri(unauthorized_hosts: &Vec<String>, uri: &Uri) -> bool { fn currently_unauthorized_hosts(config: Vec<Access>) -> Vec<String> { let now = Local::now(); + // Format spec: https://docs.rs/chrono/0.4.15/chrono/format/strftime/index.html + let day = now.format("%u").to_string().parse::<i32>().unwrap(); let hour = now.format("%H").to_string().parse::<i32>().unwrap(); let minutes = now.format("%M").to_string().parse::<i32>().unwrap(); let now = (hour, minutes); @@ -163,27 +173,65 @@ fn currently_unauthorized_hosts(config: Vec<Access>) -> Vec<String> { config .into_iter() .map(|access| { - let from = parse_time(&access.from); - let to = parse_time(&access.to); - - if is_before_or_eq(from, to) { - if is_after_or_eq(now, from) && is_before_or_eq(now, to) { - access.hosts.clone() - } else { - Vec::new() - } - } else { - if is_after_or_eq(now, from) || is_before_or_eq(now, to) { - access.hosts.clone() - } else { - Vec::new() - } - } + let Access { times, hosts } = access; + + times + .into_iter() + .map(|time| { + let days = parse_days(&time.days); + let from = parse_time(&time.from); + let to = parse_time(&time.to); + + if days.contains(&day) { + if is_before_or_eq(from, to) { + if is_after_or_eq(now, from) && is_before_or_eq(now, to) { + hosts.clone() + } else { + Vec::new() + } + } else { + if is_after_or_eq(now, from) || is_before_or_eq(now, to) { + hosts.clone() + } else { + Vec::new() + } + } + } else { + Vec::new() + } + }) + .collect::<Vec<Vec<String>>>() + .concat() }) .collect::<Vec<Vec<String>>>() .concat() } +fn parse_days(str: &str) -> Vec<i32> { + let xs = str.split("-").collect::<Vec<&str>>(); + let from = parse_day(xs[0]); + let to = parse_day(xs[1]); + (1..8).filter(|d| { + if from < to { + d >= &from && d <= &to + } else { + d >= &from || d <= &to + } + }).collect() +} + +fn parse_day(str: &str) -> i32 { + match str { + "Monday" => 1, + "Tuesday" => 2, + "Wednesday" => 3, + "Thursday" => 4, + "Friday" => 5, + "Saturday" => 6, + _ => 7, + } +} + fn parse_time(str: &str) -> (i32, i32) { let regex = Regex::new(r"(\d{2}):(\d{2})").unwrap(); match regex.captures(str) { |