summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Cargo.toml1
-rw-r--r--README.md2
-rw-r--r--src/handler.rs20
-rw-r--r--src/main.rs1
-rw-r--r--src/message.rs48
-rw-r--r--src/token.rs7
6 files changed, 55 insertions, 24 deletions
diff --git a/Cargo.toml b/Cargo.toml
index 5b183c4..e093f84 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -7,6 +7,7 @@ build = "build.rs"
[dependencies]
ascii = "0.7"
tiny_http = "0.5"
+url = "0.2"
rustc-serialize = "0.3"
time = "0.1"
rust-crypto = "0.2"
diff --git a/README.md b/README.md
index 826c929..18a98d3 100644
--- a/README.md
+++ b/README.md
@@ -28,7 +28,7 @@ Options:
proxy_pass http://127.0.0.1:8081/; # --port PORT
proxy_pass_request_body off;
proxy_set_header Content-Length "";
- proxy_set_header X-Original-URI "$scheme://$host$request_uri";
+ proxy_set_header X-Original-Url "$scheme://$host$request_uri";
proxy_set_header X-Allowed-Jid "JID1,JID2";
}
diff --git a/src/handler.rs b/src/handler.rs
index 97f5d5c..75a2359 100644
--- a/src/handler.rs
+++ b/src/handler.rs
@@ -2,7 +2,6 @@ use std::cell::Cell;
use std::collections::{HashMap};
use std::io;
use std::marker::Sync;
-use std::ops::Add;
use std::str;
use std::str::FromStr;
use std::sync::{Arc, RwLock};
@@ -23,7 +22,8 @@ pub struct HeaderInfos {
auth_username: String,
auth_password: String,
auth_method: String,
- allowed_jids: Vec<String>
+ allowed_jids: Vec<String>,
+ original_url: Option<String>
}
pub struct AuthHandler {
@@ -41,6 +41,7 @@ type EmptyResponse = Response<io::Empty>;
// HTTP Statuscodes defined as macro. This way they can be used like literals.
macro_rules! http_header_authorization { () => (r"Authorization") }
macro_rules! http_header_x_allowed_jid { () => (r"X-Allowed-Jid") }
+macro_rules! http_header_x_original_url { () => (r"X-Original-Url") }
macro_rules! http_header_www_authenticate { () => (r"WWW-Authenticate") }
// Finds a header in a `tiny_http::Header` structure.
@@ -67,11 +68,12 @@ impl AuthHandler {
}
}
- fn send_message(&self, user_jid: &str) {
+ fn send_message(&self, headerinfos: &HeaderInfos) {
+ let user_jid = &headerinfos.auth_username;
let (valid_from, valid_until, token) = self.tg.generate_token(user_jid, get_time().sec);
- let message = format_message(token, valid_from, valid_until);
+ let message = format_message(user_jid, token, valid_from, valid_until, headerinfos.original_url.clone());
if self.nosend {
- error!("Would send to {} message: {}", user_jid, message);
+ error!("Would send to {} message: {}", headerinfos.auth_username, message);
} else {
if sendxmpp::send_message(self.bot_jid.as_str(), self.bot_password.as_str(),
message.as_str(), user_jid).is_err() {
@@ -105,11 +107,15 @@ impl AuthHandler {
debug!("{}: {}", http_header_x_allowed_jid!(), allowed_jids_header);
let allowed_jids_list = allowed_jids_header.split(',').map(String::from).collect();
+ let original_url = get_header!(headers, http_header_x_original_url!())
+ .map(|v| v.value.to_string()).ok();
+
Ok(HeaderInfos {
auth_username: String::from(username),
auth_password: String::from(password),
auth_method: String::from(auth_method),
allowed_jids: allowed_jids_list,
+ original_url: original_url
})
}
@@ -139,7 +145,7 @@ impl AuthHandler {
} else {
self.last_interactive_request.set(current_time);
if is_known_user {
- self.send_message(&headerinfos.auth_username);
+ self.send_message(&headerinfos);
}
return self.authenticate_response(401) //Token sent, retry now
}
@@ -195,7 +201,7 @@ impl AuthHandler {
fn verify(&self, headerinfos: &HeaderInfos) -> Result<bool, &'static str> {
let pw_token = token::normalize_token(&headerinfos.auth_password);
let guard = self.valid_tokens_cache.clone();
- let key = headerinfos.auth_username.clone().add(":").add(pw_token.as_str());
+ let key = headerinfos.auth_username.clone() + ":" + pw_token.as_str();
let current_time = get_time().sec;
// try cache:
diff --git a/src/main.rs b/src/main.rs
index 30d4f8b..b536464 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -12,6 +12,7 @@ extern crate time;
extern crate rand;
extern crate rustc_serialize;
extern crate simple_logger;
+extern crate url;
use crypto::digest::Digest;
use crypto::sha1::Sha1;
diff --git a/src/message.rs b/src/message.rs
index 0af1a13..713e6b4 100644
--- a/src/message.rs
+++ b/src/message.rs
@@ -1,22 +1,44 @@
///! Formats the message to be sent to the user
use time::{at_utc, Timespec, strftime};
+use url::percent_encoding::{USERNAME_ENCODE_SET, PASSWORD_ENCODE_SET, percent_encode};
-
-pub fn format_message(token: String, valid_from: i64, valid_until: i64) -> String {
- return format!("Token: {}. Valid from {} until {}",
+pub fn format_message(user_jid: &str, token: String, valid_from: i64, valid_until: i64, original_url: Option<String>) -> String {
+ return format!("Token: {}. Valid from {} until {}. \n{}",
token,
strftime("%F %X", &at_utc(Timespec::new(valid_from, 0))).unwrap(),
- strftime("%F %X", &at_utc(Timespec::new(valid_until, 0))).unwrap());
+ strftime("%F %X", &at_utc(Timespec::new(valid_until, 0))).unwrap(),
+ match original_url {
+ Some(url) => insert_token_password(url, user_jid, &token),
+ None => "".to_string()
+ });
}
+fn insert_token_password(url: String, user_jid: &str, token: &str) -> String {
+ match url.find("://") {
+ Some(pos) => {
+ let (scheme, rest) = url.split_at(pos + 3);
+ return scheme.to_string() +
+ percent_encode(user_jid.as_bytes(), USERNAME_ENCODE_SET).as_str() + ":" +
+ percent_encode(token.as_bytes(), PASSWORD_ENCODE_SET).as_str() + "@" + rest;
+ },
+ None => return url
+ }
+}
-#[cfg(test)]
-mod tests {
- use super::*;
+#[test]
+fn test() {
+ assert_eq!(format_message("foo@bar.com", "7A-74-F4".to_string(), 0, 1481831953, Some("".to_string())),
+ "Token: 7A-74-F4. Valid from 1970-01-01 00:00:00 until 2016-12-15 19:59:13. \n");
+ assert_eq!(format_message("foo@bar.com", "7A-74-F4".to_string(), 0, 1481831953, Some("http".to_string())),
+ "Token: 7A-74-F4. Valid from 1970-01-01 00:00:00 until 2016-12-15 19:59:13. \nhttp");
- #[test]
- fn test1() {
- assert_eq!(format_message("7A-74-F4".to_string(), 0, 1481831953),
- "Token: 7A-74-F4. Valid from 1970-01-01 00:00:00 until 2016-12-15 19:59:13");
- }
-} \ No newline at end of file
+ assert_eq!(
+ insert_token_password(String::from("http://foo.bar/ads?123"), "user_jid", "token"),
+ "http://user_jid:token@foo.bar/ads?123");
+ assert_eq!(
+ insert_token_password(String::from("invalid"), "user_jid", "token"),
+ "invalid");
+ assert_eq!(
+ insert_token_password(String::from("http://host/path"), "user@host", "@@##"),
+ "http://user%40host:%40%40%23%23@host/path");
+}
diff --git a/src/token.rs b/src/token.rs
index 2a2e446..ff5a396 100644
--- a/src/token.rs
+++ b/src/token.rs
@@ -24,8 +24,9 @@ impl TokenGenerator {
/// Return (from, to, token)
pub fn generate_token(&self, username: &str, at_time: i64) -> (i64, i64, String) {
let timeslot = at_time - (at_time % self.valid_duration_secs);
- let input: String = format!("{}{}", username, timeslot);
- return (timeslot, timeslot + self.valid_duration_secs, self.make_hash_token(&input.as_bytes()))
+ let input = format!("{}{}", username, timeslot);
+ let token = self.make_hash_token(&input.as_bytes());
+ return (timeslot, timeslot + self.valid_duration_secs, token)
}
#[inline(always)]
@@ -64,7 +65,7 @@ mod tests {
fn test_generate_token() {
use time;
let tg = TokenGenerator::new(time::Duration::hours(2).num_seconds(),
- vec!(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16));
+ vec!(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16));
let (valid_from, valid_until, result) = tg.generate_token("a", 99999999);
assert_eq!( valid_from, 99993600);
assert_eq!( valid_until, 100000800);