aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--README.md33
-rw-r--r--src/main.rs88
2 files changed, 84 insertions, 37 deletions
diff --git a/README.md b/README.md
index 9a7445a..d047eb9 100644
--- a/README.md
+++ b/README.md
@@ -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) {