Run cargo fmt
This commit is contained in:
parent
e16eb40fd9
commit
f3ec5bd6dc
6 changed files with 324 additions and 201 deletions
|
@ -1,5 +1,4 @@
|
||||||
use csrf::{AesGcmCsrfProtection, CsrfProtection,
|
use csrf::{AesGcmCsrfProtection, CsrfProtection, CSRF_COOKIE_NAME, CSRF_FORM_FIELD};
|
||||||
CSRF_COOKIE_NAME, CSRF_FORM_FIELD};
|
|
||||||
use data_encoding::{BASE64, BASE64URL_NOPAD};
|
use data_encoding::{BASE64, BASE64URL_NOPAD};
|
||||||
use rand::prelude::thread_rng;
|
use rand::prelude::thread_rng;
|
||||||
use rand::Rng;
|
use rand::Rng;
|
||||||
|
@ -19,7 +18,8 @@ use csrf_token::CsrfToken;
|
||||||
use path::Path;
|
use path::Path;
|
||||||
use utils::parse_args;
|
use utils::parse_args;
|
||||||
|
|
||||||
const CSRF_FORM_FIELD_MULTIPART: &[u8] = "Content-Disposition: form-data; name=\"csrf-token\"".as_bytes();
|
const CSRF_FORM_FIELD_MULTIPART: &[u8] =
|
||||||
|
"Content-Disposition: form-data; name=\"csrf-token\"".as_bytes();
|
||||||
|
|
||||||
/// Builder for [CsrfFairing](struct.CsrfFairing.html)
|
/// Builder for [CsrfFairing](struct.CsrfFairing.html)
|
||||||
///
|
///
|
||||||
|
@ -321,10 +321,12 @@ impl Fairing for CsrfFairing {
|
||||||
|
|
||||||
let _ = request.guard::<CsrfToken>(); //force regeneration of csrf cookies
|
let _ = request.guard::<CsrfToken>(); //force regeneration of csrf cookies
|
||||||
|
|
||||||
let token = if request.content_type()
|
let token = if request
|
||||||
|
.content_type()
|
||||||
.map(|c| c.media_type())
|
.map(|c| c.media_type())
|
||||||
.filter(|m| m.top() == "multipart" && m.sub() == "form-data")
|
.filter(|m| m.top() == "multipart" && m.sub() == "form-data")
|
||||||
.is_some() {
|
.is_some()
|
||||||
|
{
|
||||||
data.peek().split(|&c| c==0x0A || c==0x0D)//0x0A=='\n', 0x0D=='\r'
|
data.peek().split(|&c| c==0x0A || c==0x0D)//0x0A=='\n', 0x0D=='\r'
|
||||||
.filter(|l| l.len() > 0)
|
.filter(|l| l.len() > 0)
|
||||||
.skip_while(|&l| l != CSRF_FORM_FIELD_MULTIPART && l != &CSRF_FORM_FIELD_MULTIPART[..CSRF_FORM_FIELD_MULTIPART.len()-2])
|
.skip_while(|&l| l != CSRF_FORM_FIELD_MULTIPART && l != &CSRF_FORM_FIELD_MULTIPART[..CSRF_FORM_FIELD_MULTIPART.len()-2])
|
||||||
|
@ -333,7 +335,13 @@ impl Fairing for CsrfFairing {
|
||||||
.next().unwrap_or(None)
|
.next().unwrap_or(None)
|
||||||
} else {
|
} else {
|
||||||
parse_args(from_utf8(data.peek()).unwrap_or(""))
|
parse_args(from_utf8(data.peek()).unwrap_or(""))
|
||||||
.filter_map(|(key, token)| if key == CSRF_FORM_FIELD {Some(token.as_bytes())} else {None})
|
.filter_map(|(key, token)| {
|
||||||
|
if key == CSRF_FORM_FIELD {
|
||||||
|
Some(token.as_bytes())
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
})
|
||||||
.next()
|
.next()
|
||||||
}.and_then(|token| BASE64URL_NOPAD.decode(&token).ok())
|
}.and_then(|token| BASE64URL_NOPAD.decode(&token).ok())
|
||||||
.and_then(|token| csrf_engine.parse_token(&token).ok());
|
.and_then(|token| csrf_engine.parse_token(&token).ok());
|
||||||
|
@ -379,7 +387,8 @@ impl Fairing for CsrfFairing {
|
||||||
if self
|
if self
|
||||||
.auto_insert_disable_prefix
|
.auto_insert_disable_prefix
|
||||||
.iter()
|
.iter()
|
||||||
.any(|prefix| uri.starts_with(prefix)) {
|
.any(|prefix| uri.starts_with(prefix))
|
||||||
|
{
|
||||||
return;
|
return;
|
||||||
} //if request is on an ignored prefix, ignore it
|
} //if request is on an ignored prefix, ignore it
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,7 @@
|
||||||
use std::io::{Read, Error};
|
use csrf_proxy::ParseState::*;
|
||||||
use std::cmp;
|
use std::cmp;
|
||||||
use std::collections::VecDeque;
|
use std::collections::VecDeque;
|
||||||
use csrf_proxy::ParseState::*;
|
use std::io::{Error, Read};
|
||||||
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
struct Buffer {
|
struct Buffer {
|
||||||
|
@ -43,7 +42,8 @@ impl Buffer {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn len(&self) -> usize {
|
fn len(&self) -> usize {
|
||||||
self.buf.iter().fold(0, |size, buf| size+buf.len()) - self.pos.iter().fold(0, |size, pos| size + pos)
|
self.buf.iter().fold(0, |size, buf| size + buf.len())
|
||||||
|
- self.pos.iter().fold(0, |size, pos| size + pos)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_empty(&self) -> bool {
|
fn is_empty(&self) -> bool {
|
||||||
|
@ -57,7 +57,6 @@ impl Default for Buffer {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
enum ParseState {
|
enum ParseState {
|
||||||
Init, //default state
|
Init, //default state
|
||||||
|
@ -100,17 +99,15 @@ impl<'a> CsrfProxy<'a> {
|
||||||
|
|
||||||
impl<'a> Read for CsrfProxy<'a> {
|
impl<'a> Read for CsrfProxy<'a> {
|
||||||
fn read(&mut self, buf: &mut [u8]) -> Result<usize, Error> {
|
fn read(&mut self, buf: &mut [u8]) -> Result<usize, Error> {
|
||||||
|
|
||||||
while self.buf.len() < buf.len() && !(self.eof && self.unparsed.is_empty()) {
|
while self.buf.len() < buf.len() && !(self.eof && self.unparsed.is_empty()) {
|
||||||
let len = if !self.eof {
|
let len = if !self.eof {
|
||||||
let unparsed_len = self.unparsed.len();
|
let unparsed_len = self.unparsed.len();
|
||||||
self.unparsed.resize(4096, 0);
|
self.unparsed.resize(4096, 0);
|
||||||
unparsed_len +
|
unparsed_len + match self.underlying.read(&mut self.unparsed[unparsed_len..]) {
|
||||||
match self.underlying.read(&mut self.unparsed[unparsed_len..]) {
|
|
||||||
Ok(0) => {
|
Ok(0) => {
|
||||||
self.eof = true;
|
self.eof = true;
|
||||||
0
|
0
|
||||||
},
|
}
|
||||||
Ok(len) => len,
|
Ok(len) => len,
|
||||||
Err(e) => return Err(e),
|
Err(e) => return Err(e),
|
||||||
}
|
}
|
||||||
|
@ -137,9 +134,11 @@ impl<'a> Read for CsrfProxy<'a> {
|
||||||
consumed += buf.len();
|
consumed += buf.len();
|
||||||
Init
|
Init
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
PartialFormMatch => {
|
PartialFormMatch => {
|
||||||
if let Some(lower_begin) = buf.get(1..5).map(|slice| slice.to_ascii_lowercase()) {
|
if let Some(lower_begin) =
|
||||||
|
buf.get(1..5).map(|slice| slice.to_ascii_lowercase())
|
||||||
|
{
|
||||||
buf = &buf[5..];
|
buf = &buf[5..];
|
||||||
consumed += 5;
|
consumed += 5;
|
||||||
if lower_begin == "form".as_bytes() {
|
if lower_begin == "form".as_bytes() {
|
||||||
|
@ -151,7 +150,7 @@ impl<'a> Read for CsrfProxy<'a> {
|
||||||
leave = true;
|
leave = true;
|
||||||
PartialFormMatch
|
PartialFormMatch
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
SearchFormElem => {
|
SearchFormElem => {
|
||||||
if let Some(tag_pos) = buf.iter().position(|&c| c as char == '<') {
|
if let Some(tag_pos) = buf.iter().position(|&c| c as char == '<') {
|
||||||
buf = &buf[tag_pos..];
|
buf = &buf[tag_pos..];
|
||||||
|
@ -161,13 +160,17 @@ impl<'a> Read for CsrfProxy<'a> {
|
||||||
leave = true;
|
leave = true;
|
||||||
consumed += buf.len();
|
consumed += buf.len();
|
||||||
SearchFormElem
|
SearchFormElem
|
||||||
}},
|
}
|
||||||
|
}
|
||||||
PartialFormElemMatch => {
|
PartialFormElemMatch => {
|
||||||
if let Some(lower_begin) = buf.get(1..9).map(|slice| slice.to_ascii_lowercase()) {
|
if let Some(lower_begin) =
|
||||||
|
buf.get(1..9).map(|slice| slice.to_ascii_lowercase())
|
||||||
|
{
|
||||||
if lower_begin.starts_with("/form".as_bytes())
|
if lower_begin.starts_with("/form".as_bytes())
|
||||||
|| lower_begin.starts_with("textarea".as_bytes())
|
|| lower_begin.starts_with("textarea".as_bytes())
|
||||||
|| lower_begin.starts_with("button".as_bytes())
|
|| lower_begin.starts_with("button".as_bytes())
|
||||||
|| lower_begin.starts_with("select".as_bytes()) {
|
|| lower_begin.starts_with("select".as_bytes())
|
||||||
|
{
|
||||||
insert_token = true;
|
insert_token = true;
|
||||||
leave = true;
|
leave = true;
|
||||||
Init
|
Init
|
||||||
|
@ -182,12 +185,16 @@ impl<'a> Read for CsrfProxy<'a> {
|
||||||
leave = true;
|
leave = true;
|
||||||
SearchFormElem
|
SearchFormElem
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
SearchMethod(pos) => {
|
SearchMethod(pos) => {
|
||||||
if let Some(meth_pos) = buf[pos..].iter().position(|&c| c as char == ' ' || c as char == '>') {
|
if let Some(meth_pos) = buf[pos..]
|
||||||
|
.iter()
|
||||||
|
.position(|&c| c as char == ' ' || c as char == '>')
|
||||||
|
{
|
||||||
if buf[meth_pos + pos] as char == ' ' {
|
if buf[meth_pos + pos] as char == ' ' {
|
||||||
PartialNameMatch(meth_pos + pos + 1)
|
PartialNameMatch(meth_pos + pos + 1)
|
||||||
} else { //reached '>'
|
} else {
|
||||||
|
//reached '>'
|
||||||
insert_token = true;
|
insert_token = true;
|
||||||
leave = true;
|
leave = true;
|
||||||
Init
|
Init
|
||||||
|
@ -196,11 +203,15 @@ impl<'a> Read for CsrfProxy<'a> {
|
||||||
leave = true;
|
leave = true;
|
||||||
SearchMethod(buf.len())
|
SearchMethod(buf.len())
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
PartialNameMatch(pos) => {
|
PartialNameMatch(pos) => {
|
||||||
if let Some(lower_begin) = buf.get(pos..pos+14).map(|slice| slice.to_ascii_lowercase()) {
|
if let Some(lower_begin) = buf
|
||||||
|
.get(pos..pos + 14)
|
||||||
|
.map(|slice| slice.to_ascii_lowercase())
|
||||||
|
{
|
||||||
if lower_begin.starts_with("name=\"_method\"".as_bytes())
|
if lower_begin.starts_with("name=\"_method\"".as_bytes())
|
||||||
|| lower_begin.starts_with("name='_method'".as_bytes()) {
|
|| lower_begin.starts_with("name='_method'".as_bytes())
|
||||||
|
{
|
||||||
buf = &buf[pos + 14..];
|
buf = &buf[pos + 14..];
|
||||||
consumed += pos + 14;
|
consumed += pos + 14;
|
||||||
CloseInputTag
|
CloseInputTag
|
||||||
|
@ -215,7 +226,7 @@ impl<'a> Read for CsrfProxy<'a> {
|
||||||
leave = true;
|
leave = true;
|
||||||
PartialNameMatch(pos)
|
PartialNameMatch(pos)
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
CloseInputTag => {
|
CloseInputTag => {
|
||||||
leave = true;
|
leave = true;
|
||||||
if let Some(tag_pos) = buf.iter().position(|&c| c as char == '>') {
|
if let Some(tag_pos) = buf.iter().position(|&c| c as char == '>') {
|
||||||
|
@ -227,7 +238,7 @@ impl<'a> Read for CsrfProxy<'a> {
|
||||||
consumed += buf.len();
|
consumed += buf.len();
|
||||||
CloseInputTag
|
CloseInputTag
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
(consumed, insert_token)
|
(consumed, insert_token)
|
||||||
|
@ -305,7 +316,8 @@ mod tests{
|
||||||
<body>
|
<body>
|
||||||
Body of this simple doc
|
Body of this simple doc
|
||||||
</body>
|
</body>
|
||||||
</html>".as_bytes();
|
</html>"
|
||||||
|
.as_bytes();
|
||||||
let mut proxy = CsrfProxy::from(Box::new(Cursor::new(data)), "abcd".as_bytes());
|
let mut proxy = CsrfProxy::from(Box::new(Cursor::new(data)), "abcd".as_bytes());
|
||||||
let mut pr_data = Vec::new();
|
let mut pr_data = Vec::new();
|
||||||
let read = proxy.read_to_end(&mut pr_data);
|
let read = proxy.read_to_end(&mut pr_data);
|
||||||
|
@ -327,7 +339,8 @@ mod tests{
|
||||||
</p>
|
</p>
|
||||||
</form>
|
</form>
|
||||||
</body>
|
</body>
|
||||||
</html>".as_bytes();
|
</html>"
|
||||||
|
.as_bytes();
|
||||||
let expected = "<!DOCTYPE html>
|
let expected = "<!DOCTYPE html>
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
|
@ -340,11 +353,15 @@ mod tests{
|
||||||
</p>
|
</p>
|
||||||
<input type=\"hidden\" name=\"csrf-token\" value=\"abcd\"/></form>
|
<input type=\"hidden\" name=\"csrf-token\" value=\"abcd\"/></form>
|
||||||
</body>
|
</body>
|
||||||
</html>".as_bytes();
|
</html>"
|
||||||
|
.as_bytes();
|
||||||
let mut proxy = CsrfProxy::from(Box::new(Cursor::new(data)), "abcd".as_bytes());
|
let mut proxy = CsrfProxy::from(Box::new(Cursor::new(data)), "abcd".as_bytes());
|
||||||
let mut pr_data = Vec::new();
|
let mut pr_data = Vec::new();
|
||||||
let read = proxy.read_to_end(&mut pr_data);
|
let read = proxy.read_to_end(&mut pr_data);
|
||||||
assert_eq!(read.unwrap(), data.len() + "<input type=\"hidden\" name=\"csrf-token\" value=\"abcd\"/>".len());
|
assert_eq!(
|
||||||
|
read.unwrap(),
|
||||||
|
data.len() + "<input type=\"hidden\" name=\"csrf-token\" value=\"abcd\"/>".len()
|
||||||
|
);
|
||||||
assert_eq!(&pr_data, &expected)
|
assert_eq!(&pr_data, &expected)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -360,7 +377,8 @@ mod tests{
|
||||||
<input name=\"name\"/>
|
<input name=\"name\"/>
|
||||||
</form>
|
</form>
|
||||||
</body>
|
</body>
|
||||||
</html>".as_bytes();
|
</html>"
|
||||||
|
.as_bytes();
|
||||||
let expected = "<!DOCTYPE html>
|
let expected = "<!DOCTYPE html>
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
|
@ -371,11 +389,15 @@ mod tests{
|
||||||
<input type=\"hidden\" name=\"csrf-token\" value=\"abcd\"/><input name=\"name\"/>
|
<input type=\"hidden\" name=\"csrf-token\" value=\"abcd\"/><input name=\"name\"/>
|
||||||
</form>
|
</form>
|
||||||
</body>
|
</body>
|
||||||
</html>".as_bytes();
|
</html>"
|
||||||
|
.as_bytes();
|
||||||
let mut proxy = CsrfProxy::from(Box::new(Cursor::new(data)), "abcd".as_bytes());
|
let mut proxy = CsrfProxy::from(Box::new(Cursor::new(data)), "abcd".as_bytes());
|
||||||
let mut pr_data = Vec::new();
|
let mut pr_data = Vec::new();
|
||||||
let read = proxy.read_to_end(&mut pr_data);
|
let read = proxy.read_to_end(&mut pr_data);
|
||||||
assert_eq!(read.unwrap(), data.len() + "<input type=\"hidden\" name=\"csrf-token\" value=\"abcd\"/>".len());
|
assert_eq!(
|
||||||
|
read.unwrap(),
|
||||||
|
data.len() + "<input type=\"hidden\" name=\"csrf-token\" value=\"abcd\"/>".len()
|
||||||
|
);
|
||||||
assert_eq!(&pr_data, &expected)
|
assert_eq!(&pr_data, &expected)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -391,7 +413,8 @@ mod tests{
|
||||||
<input name=\"_method\"/>
|
<input name=\"_method\"/>
|
||||||
</form>
|
</form>
|
||||||
</body>
|
</body>
|
||||||
</html>".as_bytes();
|
</html>"
|
||||||
|
.as_bytes();
|
||||||
let expected = "<!DOCTYPE html>
|
let expected = "<!DOCTYPE html>
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
|
@ -402,11 +425,15 @@ mod tests{
|
||||||
<input name=\"_method\"/><input type=\"hidden\" name=\"csrf-token\" value=\"abcd\"/>
|
<input name=\"_method\"/><input type=\"hidden\" name=\"csrf-token\" value=\"abcd\"/>
|
||||||
</form>
|
</form>
|
||||||
</body>
|
</body>
|
||||||
</html>".as_bytes();
|
</html>"
|
||||||
|
.as_bytes();
|
||||||
let mut proxy = CsrfProxy::from(Box::new(Cursor::new(data)), "abcd".as_bytes());
|
let mut proxy = CsrfProxy::from(Box::new(Cursor::new(data)), "abcd".as_bytes());
|
||||||
let mut pr_data = Vec::new();
|
let mut pr_data = Vec::new();
|
||||||
let read = proxy.read_to_end(&mut pr_data);
|
let read = proxy.read_to_end(&mut pr_data);
|
||||||
assert_eq!(read.unwrap(), data.len() + "<input type=\"hidden\" name=\"csrf-token\" value=\"abcd\"/>".len());
|
assert_eq!(
|
||||||
|
read.unwrap(),
|
||||||
|
data.len() + "<input type=\"hidden\" name=\"csrf-token\" value=\"abcd\"/>".len()
|
||||||
|
);
|
||||||
assert_eq!(&pr_data, &expected)
|
assert_eq!(&pr_data, &expected)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -424,7 +451,10 @@ mod tests{
|
||||||
let err = ErrorReader {};
|
let err = ErrorReader {};
|
||||||
let mut proxy_err = CsrfProxy::from(Box::new(err), &[0]);
|
let mut proxy_err = CsrfProxy::from(Box::new(err), &[0]);
|
||||||
let read = proxy_err.read(buf).unwrap_err();
|
let read = proxy_err.read(buf).unwrap_err();
|
||||||
assert_eq!(read.kind(), ::std::io::Error::new(::std::io::ErrorKind::Other, "").kind());
|
assert_eq!(
|
||||||
|
read.kind(),
|
||||||
|
::std::io::Error::new(::std::io::ErrorKind::Other, "").kind()
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct SlowReader<'a> {
|
struct SlowReader<'a> {
|
||||||
|
@ -444,7 +474,8 @@ mod tests{
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_difficult_cut() {//this basically re-test the parser, using short reads so it encounter rare code paths
|
fn test_difficult_cut() {
|
||||||
|
//this basically re-test the parser, using short reads so it encounter rare code paths
|
||||||
let data = "<!DOCTYPE html>
|
let data = "<!DOCTYPE html>
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
|
@ -457,7 +488,8 @@ mod tests{
|
||||||
</p>
|
</p>
|
||||||
</form>
|
</form>
|
||||||
</body>
|
</body>
|
||||||
</html>".as_bytes();
|
</html>"
|
||||||
|
.as_bytes();
|
||||||
let expected = "<!DOCTYPE html>
|
let expected = "<!DOCTYPE html>
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
|
@ -470,11 +502,15 @@ mod tests{
|
||||||
</p>
|
</p>
|
||||||
<input type=\"hidden\" name=\"csrf-token\" value=\"abcd\"/></form>
|
<input type=\"hidden\" name=\"csrf-token\" value=\"abcd\"/></form>
|
||||||
</body>
|
</body>
|
||||||
</html>".as_bytes();
|
</html>"
|
||||||
|
.as_bytes();
|
||||||
let mut proxy = CsrfProxy::from(Box::new(SlowReader { content: data }), "abcd".as_bytes());
|
let mut proxy = CsrfProxy::from(Box::new(SlowReader { content: data }), "abcd".as_bytes());
|
||||||
let mut pr_data = Vec::new();
|
let mut pr_data = Vec::new();
|
||||||
let read = proxy.read_to_end(&mut pr_data);
|
let read = proxy.read_to_end(&mut pr_data);
|
||||||
assert_eq!(read.unwrap(), data.len() + "<input type=\"hidden\" name=\"csrf-token\" value=\"abcd\"/>".len());
|
assert_eq!(
|
||||||
|
read.unwrap(),
|
||||||
|
data.len() + "<input type=\"hidden\" name=\"csrf-token\" value=\"abcd\"/>".len()
|
||||||
|
);
|
||||||
assert_eq!(&pr_data, &expected);
|
assert_eq!(&pr_data, &expected);
|
||||||
|
|
||||||
let data = "<!DOCTYPE html>
|
let data = "<!DOCTYPE html>
|
||||||
|
@ -487,7 +523,8 @@ mod tests{
|
||||||
<input name=\"name\"/>
|
<input name=\"name\"/>
|
||||||
</form>
|
</form>
|
||||||
</body>
|
</body>
|
||||||
</html>".as_bytes();
|
</html>"
|
||||||
|
.as_bytes();
|
||||||
let expected = "<!DOCTYPE html>
|
let expected = "<!DOCTYPE html>
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
|
@ -498,11 +535,15 @@ mod tests{
|
||||||
<input type=\"hidden\" name=\"csrf-token\" value=\"abcd\"/><input name=\"name\"/>
|
<input type=\"hidden\" name=\"csrf-token\" value=\"abcd\"/><input name=\"name\"/>
|
||||||
</form>
|
</form>
|
||||||
</body>
|
</body>
|
||||||
</html>".as_bytes();
|
</html>"
|
||||||
|
.as_bytes();
|
||||||
let mut proxy = CsrfProxy::from(Box::new(SlowReader { content: data }), "abcd".as_bytes());
|
let mut proxy = CsrfProxy::from(Box::new(SlowReader { content: data }), "abcd".as_bytes());
|
||||||
let mut pr_data = Vec::new();
|
let mut pr_data = Vec::new();
|
||||||
let read = proxy.read_to_end(&mut pr_data);
|
let read = proxy.read_to_end(&mut pr_data);
|
||||||
assert_eq!(read.unwrap(), data.len() + "<input type=\"hidden\" name=\"csrf-token\" value=\"abcd\"/>".len());
|
assert_eq!(
|
||||||
|
read.unwrap(),
|
||||||
|
data.len() + "<input type=\"hidden\" name=\"csrf-token\" value=\"abcd\"/>".len()
|
||||||
|
);
|
||||||
assert_eq!(&pr_data, &expected);
|
assert_eq!(&pr_data, &expected);
|
||||||
|
|
||||||
let data = "<!DOCTYPE html>
|
let data = "<!DOCTYPE html>
|
||||||
|
@ -515,7 +556,8 @@ mod tests{
|
||||||
<input name=\"_method\"/>
|
<input name=\"_method\"/>
|
||||||
</form>
|
</form>
|
||||||
</body>
|
</body>
|
||||||
</html>".as_bytes();
|
</html>"
|
||||||
|
.as_bytes();
|
||||||
let expected = "<!DOCTYPE html>
|
let expected = "<!DOCTYPE html>
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
|
@ -526,11 +568,15 @@ mod tests{
|
||||||
<input name=\"_method\"/><input type=\"hidden\" name=\"csrf-token\" value=\"abcd\"/>
|
<input name=\"_method\"/><input type=\"hidden\" name=\"csrf-token\" value=\"abcd\"/>
|
||||||
</form>
|
</form>
|
||||||
</body>
|
</body>
|
||||||
</html>".as_bytes();
|
</html>"
|
||||||
|
.as_bytes();
|
||||||
let mut proxy = CsrfProxy::from(Box::new(SlowReader { content: data }), "abcd".as_bytes());
|
let mut proxy = CsrfProxy::from(Box::new(SlowReader { content: data }), "abcd".as_bytes());
|
||||||
let mut pr_data = Vec::new();
|
let mut pr_data = Vec::new();
|
||||||
let read = proxy.read_to_end(&mut pr_data);
|
let read = proxy.read_to_end(&mut pr_data);
|
||||||
assert_eq!(read.unwrap(), data.len() + "<input type=\"hidden\" name=\"csrf-token\" value=\"abcd\"/>".len());
|
assert_eq!(
|
||||||
|
read.unwrap(),
|
||||||
|
data.len() + "<input type=\"hidden\" name=\"csrf-token\" value=\"abcd\"/>".len()
|
||||||
|
);
|
||||||
assert_eq!(&pr_data, &expected)
|
assert_eq!(&pr_data, &expected)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
use csrf::{AesGcmCsrfProtection, CsrfProtection, CSRF_COOKIE_NAME};
|
use csrf::{AesGcmCsrfProtection, CsrfProtection, CSRF_COOKIE_NAME};
|
||||||
use data_encoding::{BASE64, BASE64URL_NOPAD};
|
use data_encoding::{BASE64, BASE64URL_NOPAD};
|
||||||
use rocket::{Request, State};
|
|
||||||
use rocket::http::{Cookie, Status};
|
use rocket::http::{Cookie, Status};
|
||||||
use rocket::outcome::Outcome;
|
use rocket::outcome::Outcome;
|
||||||
use rocket::request::{self, FromRequest};
|
use rocket::request::{self, FromRequest};
|
||||||
|
use rocket::{Request, State};
|
||||||
use serde::{Serialize, Serializer};
|
use serde::{Serialize, Serializer};
|
||||||
use time::Duration;
|
use time::Duration;
|
||||||
|
|
||||||
|
|
|
@ -49,11 +49,11 @@ extern crate rocket;
|
||||||
extern crate serde;
|
extern crate serde;
|
||||||
extern crate time;
|
extern crate time;
|
||||||
|
|
||||||
mod csrf_proxy;
|
|
||||||
mod csrf_fairing;
|
mod csrf_fairing;
|
||||||
|
mod csrf_proxy;
|
||||||
mod csrf_token;
|
mod csrf_token;
|
||||||
mod path;
|
mod path;
|
||||||
mod utils;
|
mod utils;
|
||||||
|
|
||||||
pub use self::csrf_fairing::{CsrfFairingBuilder, CsrfFairing};
|
pub use self::csrf_fairing::{CsrfFairing, CsrfFairingBuilder};
|
||||||
pub use self::csrf_token::CsrfToken;
|
pub use self::csrf_token::CsrfToken;
|
||||||
|
|
128
src/path.rs
128
src/path.rs
|
@ -30,15 +30,20 @@ impl Path {
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
if path[0..path.len()-1].iter().any(|a|
|
if path[0..path.len() - 1].iter().any(|a| {
|
||||||
if let PathPart::MultiDynamic(_) = a {true} else {false}
|
if let PathPart::MultiDynamic(_) = a {
|
||||||
) {
|
true
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}) {
|
||||||
panic!("PathPart::MultiDynamic can only be found at end of path"); //TODO return error instead of panic
|
panic!("PathPart::MultiDynamic can only be found at end of path"); //TODO return error instead of panic
|
||||||
}
|
}
|
||||||
|
|
||||||
let param = query.map(|query| {
|
let param = query.map(|query| {
|
||||||
parse_args(query)
|
parse_args(query)
|
||||||
.map(|(k, v)| {(
|
.map(|(k, v)| {
|
||||||
|
(
|
||||||
k.to_owned(),
|
k.to_owned(),
|
||||||
if v.starts_with('<') && v.ends_with("..>") {
|
if v.starts_with('<') && v.ends_with("..>") {
|
||||||
panic!("PathPart::MultiDynamic is invalid in query part");
|
panic!("PathPart::MultiDynamic is invalid in query part");
|
||||||
|
@ -52,10 +57,7 @@ impl Path {
|
||||||
})
|
})
|
||||||
.collect()
|
.collect()
|
||||||
});
|
});
|
||||||
Path {
|
Path { path, param }
|
||||||
path,
|
|
||||||
param,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn extract<'a>(&self, uri: &'a str) -> Option<HashMap<&str, String>> {
|
pub fn extract<'a>(&self, uri: &'a str) -> Option<HashMap<&str, String>> {
|
||||||
|
@ -78,18 +80,18 @@ impl Path {
|
||||||
//static, but not the same, fail to parse
|
//static, but not the same, fail to parse
|
||||||
if let Some(val) = path.next() {
|
if let Some(val) = path.next() {
|
||||||
if val != reference {
|
if val != reference {
|
||||||
return None
|
return None;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return None
|
return None;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
|
||||||
PathPart::Dynamic(key) => {
|
PathPart::Dynamic(key) => {
|
||||||
//dynamic, store to hashmap
|
//dynamic, store to hashmap
|
||||||
if let Some(val) = path.next() {
|
if let Some(val) = path.next() {
|
||||||
res.insert(key, val.to_owned());
|
res.insert(key, val.to_owned());
|
||||||
} else {
|
} else {
|
||||||
return None
|
return None;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
PathPart::MultiDynamic(key) => {
|
PathPart::MultiDynamic(key) => {
|
||||||
|
@ -120,7 +122,9 @@ impl Path {
|
||||||
//dynamic, store to hashmap
|
//dynamic, store to hashmap
|
||||||
res.insert(key, hm.get::<&str>(&(k as &str))?.to_string());
|
res.insert(key, hm.get::<&str>(&(k as &str))?.to_string());
|
||||||
}
|
}
|
||||||
PathPart::MultiDynamic(_) => panic!("PathPart::MultiDynamic is invalid in query part"),
|
PathPart::MultiDynamic(_) => {
|
||||||
|
panic!("PathPart::MultiDynamic is invalid in query part")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -143,7 +147,9 @@ impl Path {
|
||||||
res.push('/');
|
res.push('/');
|
||||||
match seg {
|
match seg {
|
||||||
PathPart::Static(val) => res.push_str(val),
|
PathPart::Static(val) => res.push_str(val),
|
||||||
PathPart::Dynamic(val) | PathPart::MultiDynamic(val) => res.push_str(param.get::<str>(val)?),
|
PathPart::Dynamic(val) | PathPart::MultiDynamic(val) => {
|
||||||
|
res.push_str(param.get::<str>(val)?)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if let Some(ref keymap) = self.param {
|
if let Some(ref keymap) = self.param {
|
||||||
|
@ -155,7 +161,9 @@ impl Path {
|
||||||
match v {
|
match v {
|
||||||
PathPart::Static(val) => res.push_str(val),
|
PathPart::Static(val) => res.push_str(val),
|
||||||
PathPart::Dynamic(val) => res.push_str(param.get::<str>(val)?),
|
PathPart::Dynamic(val) => res.push_str(param.get::<str>(val)?),
|
||||||
PathPart::MultiDynamic(_) => panic!("PathPart::MultiDynamic is invalid in query part"),
|
PathPart::MultiDynamic(_) => {
|
||||||
|
panic!("PathPart::MultiDynamic is invalid in query part")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
res.push('&');
|
res.push('&');
|
||||||
}
|
}
|
||||||
|
@ -197,33 +205,58 @@ mod tests{
|
||||||
fn test_static_path_with_query() {
|
fn test_static_path_with_query() {
|
||||||
let query = Path::from("/path/query?param=value¶m2=value2");
|
let query = Path::from("/path/query?param=value¶m2=value2");
|
||||||
assert!(query.extract("/path/query").is_none());
|
assert!(query.extract("/path/query").is_none());
|
||||||
assert!(query.extract("/path/other?param=value¶m2=value2").is_none());
|
assert!(
|
||||||
assert!(query.extract("/path/query/longer?param=value¶m2=value2").is_none());
|
query
|
||||||
|
.extract("/path/other?param=value¶m2=value2")
|
||||||
|
.is_none()
|
||||||
|
);
|
||||||
|
assert!(
|
||||||
|
query
|
||||||
|
.extract("/path/query/longer?param=value¶m2=value2")
|
||||||
|
.is_none()
|
||||||
|
);
|
||||||
assert!(query.extract("/path?param=value¶m2=value2").is_none());
|
assert!(query.extract("/path?param=value¶m2=value2").is_none());
|
||||||
|
|
||||||
let hashmap = query.extract("/path/query?param=value¶m2=value2").unwrap();
|
let hashmap = query
|
||||||
|
.extract("/path/query?param=value¶m2=value2")
|
||||||
|
.unwrap();
|
||||||
assert_eq!(hashmap.len(), 0);
|
assert_eq!(hashmap.len(), 0);
|
||||||
|
|
||||||
let hashmap = query.extract("/path/query?param2=value2¶m=value").unwrap();
|
let hashmap = query
|
||||||
|
.extract("/path/query?param2=value2¶m=value")
|
||||||
|
.unwrap();
|
||||||
assert_eq!(hashmap.len(), 0);
|
assert_eq!(hashmap.len(), 0);
|
||||||
|
|
||||||
let uri = query.map(&HashMap::new()).unwrap();
|
let uri = query.map(&HashMap::new()).unwrap();
|
||||||
assert!(uri=="/path/query?param=value¶m2=value2" || uri=="/path/query?param2=value2¶m=value");
|
assert!(
|
||||||
|
uri == "/path/query?param=value¶m2=value2"
|
||||||
|
|| uri == "/path/query?param2=value2¶m=value"
|
||||||
|
);
|
||||||
|
|
||||||
let mut hashmap = HashMap::new();
|
let mut hashmap = HashMap::new();
|
||||||
hashmap.insert("key", "value".to_owned());
|
hashmap.insert("key", "value".to_owned());
|
||||||
let uri = query.map(&hashmap).unwrap();
|
let uri = query.map(&hashmap).unwrap();
|
||||||
assert!(uri=="/path/query?param=value¶m2=value2" || uri=="/path/query?param2=value2¶m=value");
|
assert!(
|
||||||
|
uri == "/path/query?param=value¶m2=value2"
|
||||||
|
|| uri == "/path/query?param2=value2¶m=value"
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_dynamic_path_without_query() {
|
fn test_dynamic_path_without_query() {
|
||||||
let no_query = Path::from("/path/<with>/<dynamic>/values");
|
let no_query = Path::from("/path/<with>/<dynamic>/values");
|
||||||
assert!(no_query.extract("/path/with/dynamic/values/longer").is_none());
|
assert!(
|
||||||
|
no_query
|
||||||
|
.extract("/path/with/dynamic/values/longer")
|
||||||
|
.is_none()
|
||||||
|
);
|
||||||
assert!(no_query.extract("/path/with/dynamic").is_none());
|
assert!(no_query.extract("/path/with/dynamic").is_none());
|
||||||
assert!(no_query.extract("/path/with/dynamic/non_value").is_none());
|
assert!(no_query.extract("/path/with/dynamic/non_value").is_none());
|
||||||
assert!(no_query.extract("/path/with/dynamic/values?and=query").is_none());
|
assert!(
|
||||||
|
no_query
|
||||||
|
.extract("/path/with/dynamic/values?and=query")
|
||||||
|
.is_none()
|
||||||
|
);
|
||||||
|
|
||||||
let hashmap = no_query.extract("/path/containing/moving/values").unwrap();
|
let hashmap = no_query.extract("/path/containing/moving/values").unwrap();
|
||||||
assert_eq!(hashmap.len(), 2);
|
assert_eq!(hashmap.len(), 2);
|
||||||
|
@ -235,23 +268,37 @@ mod tests{
|
||||||
let mut hashmap = HashMap::new();
|
let mut hashmap = HashMap::new();
|
||||||
hashmap.insert("with", "with".to_owned());
|
hashmap.insert("with", "with".to_owned());
|
||||||
hashmap.insert("dynamic", "non_static".to_owned());
|
hashmap.insert("dynamic", "non_static".to_owned());
|
||||||
assert_eq!(no_query.map(&hashmap).unwrap(), "/path/with/non_static/values");
|
assert_eq!(
|
||||||
|
no_query.map(&hashmap).unwrap(),
|
||||||
|
"/path/with/non_static/values"
|
||||||
|
);
|
||||||
hashmap.insert("random", "value".to_owned());
|
hashmap.insert("random", "value".to_owned());
|
||||||
assert_eq!(no_query.map(&hashmap).unwrap(), "/path/with/non_static/values");
|
assert_eq!(
|
||||||
|
no_query.map(&hashmap).unwrap(),
|
||||||
|
"/path/with/non_static/values"
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_dynamic_path_with_query() {
|
fn test_dynamic_path_with_query() {
|
||||||
let query = Path::from("/path/<with>/<dynamic>/values?key=<value>&static=static");
|
let query = Path::from("/path/<with>/<dynamic>/values?key=<value>&static=static");
|
||||||
assert!(query.extract("/path/with/dynamic/values?key=something&static=error").is_none());
|
assert!(
|
||||||
|
query
|
||||||
|
.extract("/path/with/dynamic/values?key=something&static=error")
|
||||||
|
.is_none()
|
||||||
|
);
|
||||||
|
|
||||||
let hashmap = query.extract("/path/containing/moving/values?key=val&static=static").unwrap();
|
let hashmap = query
|
||||||
|
.extract("/path/containing/moving/values?key=val&static=static")
|
||||||
|
.unwrap();
|
||||||
assert_eq!(hashmap.len(), 3);
|
assert_eq!(hashmap.len(), 3);
|
||||||
assert_eq!(hashmap.get("with").unwrap(), "containing");
|
assert_eq!(hashmap.get("with").unwrap(), "containing");
|
||||||
assert_eq!(hashmap.get("dynamic").unwrap(), "moving");
|
assert_eq!(hashmap.get("dynamic").unwrap(), "moving");
|
||||||
assert_eq!(hashmap.get("value").unwrap(), "val");
|
assert_eq!(hashmap.get("value").unwrap(), "val");
|
||||||
|
|
||||||
let hashmap = query.extract("/path/containing/moving/values?static=static&key=val").unwrap();
|
let hashmap = query
|
||||||
|
.extract("/path/containing/moving/values?static=static&key=val")
|
||||||
|
.unwrap();
|
||||||
assert_eq!(hashmap.len(), 3);
|
assert_eq!(hashmap.len(), 3);
|
||||||
assert_eq!(hashmap.get("with").unwrap(), "containing");
|
assert_eq!(hashmap.get("with").unwrap(), "containing");
|
||||||
assert_eq!(hashmap.get("dynamic").unwrap(), "moving");
|
assert_eq!(hashmap.get("dynamic").unwrap(), "moving");
|
||||||
|
@ -263,9 +310,19 @@ mod tests{
|
||||||
hashmap.insert("with", "with".to_owned());
|
hashmap.insert("with", "with".to_owned());
|
||||||
hashmap.insert("dynamic", "non_static".to_owned());
|
hashmap.insert("dynamic", "non_static".to_owned());
|
||||||
hashmap.insert("value", "something".to_owned());
|
hashmap.insert("value", "something".to_owned());
|
||||||
assert!(query.map(&hashmap).unwrap()=="/path/with/non_static/values?key=something&static=static" || query.map(&hashmap).unwrap()=="/path/with/non_static/values?static=static&key=something");
|
assert!(
|
||||||
|
query.map(&hashmap).unwrap()
|
||||||
|
== "/path/with/non_static/values?key=something&static=static"
|
||||||
|
|| query.map(&hashmap).unwrap()
|
||||||
|
== "/path/with/non_static/values?static=static&key=something"
|
||||||
|
);
|
||||||
hashmap.insert("random", "value".to_owned());
|
hashmap.insert("random", "value".to_owned());
|
||||||
assert!(query.map(&hashmap).unwrap()=="/path/with/non_static/values?key=something&static=static" || query.map(&hashmap).unwrap()=="/path/with/non_static/values?static=static&key=something");
|
assert!(
|
||||||
|
query.map(&hashmap).unwrap()
|
||||||
|
== "/path/with/non_static/values?key=something&static=static"
|
||||||
|
|| query.map(&hashmap).unwrap()
|
||||||
|
== "/path/with/non_static/values?static=static&key=something"
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -288,12 +345,17 @@ mod tests{
|
||||||
assert_eq!(hashmap.len(), 1);
|
assert_eq!(hashmap.len(), 1);
|
||||||
assert_eq!(hashmap.get("multidyn").unwrap(), "");
|
assert_eq!(hashmap.get("multidyn").unwrap(), "");
|
||||||
|
|
||||||
let hashmap = query.extract("/path/longer/than/before?static=static").unwrap();
|
let hashmap = query
|
||||||
|
.extract("/path/longer/than/before?static=static")
|
||||||
|
.unwrap();
|
||||||
assert_eq!(hashmap.len(), 1);
|
assert_eq!(hashmap.len(), 1);
|
||||||
assert_eq!(hashmap.get("multidyn").unwrap(), "longer/than/before");
|
assert_eq!(hashmap.get("multidyn").unwrap(), "longer/than/before");
|
||||||
|
|
||||||
let mut hashmap = HashMap::new();
|
let mut hashmap = HashMap::new();
|
||||||
hashmap.insert("multidyn", "something".to_owned());
|
hashmap.insert("multidyn", "something".to_owned());
|
||||||
assert_eq!(query.map(&hashmap).unwrap(), "/path/something?static=static");
|
assert_eq!(
|
||||||
|
query.map(&hashmap).unwrap(),
|
||||||
|
"/path/something?static=static"
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
12
src/utils.rs
12
src/utils.rs
|
@ -15,16 +15,22 @@ fn parse_keyvalue(kv: &str) -> Option<(&str, &str)> {
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use utils::{parse_keyvalue, parse_args};
|
use utils::{parse_args, parse_keyvalue};
|
||||||
#[test]
|
#[test]
|
||||||
fn test_parse_keyvalue() {
|
fn test_parse_keyvalue() {
|
||||||
assert_eq!(parse_keyvalue("a_key=a_value").unwrap(),("a_key", "a_value"));
|
assert_eq!(
|
||||||
|
parse_keyvalue("a_key=a_value").unwrap(),
|
||||||
|
("a_key", "a_value")
|
||||||
|
);
|
||||||
|
|
||||||
assert_eq!(parse_keyvalue("=a_value").unwrap(), ("", "a_value"));
|
assert_eq!(parse_keyvalue("=a_value").unwrap(), ("", "a_value"));
|
||||||
|
|
||||||
assert_eq!(parse_keyvalue("a_key=").unwrap(), ("a_key", ""));
|
assert_eq!(parse_keyvalue("a_key=").unwrap(), ("a_key", ""));
|
||||||
|
|
||||||
assert_eq!(parse_keyvalue("a_key=a=value").unwrap(),("a_key", "a=value"));
|
assert_eq!(
|
||||||
|
parse_keyvalue("a_key=a=value").unwrap(),
|
||||||
|
("a_key", "a=value")
|
||||||
|
);
|
||||||
|
|
||||||
assert_eq!(parse_keyvalue("=").unwrap(), ("", ""));
|
assert_eq!(parse_keyvalue("=").unwrap(), ("", ""));
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue