server: add better validation to the associations endpoint (#194)

pull/195/head
Jake McGinty 2022-02-01 13:53:31 +09:00 committed by GitHub
parent 54131b4447
commit b6ce16bc00
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 124 additions and 0 deletions

View File

@ -57,6 +57,30 @@ impl DatabaseAssociation {
cidr_id_2, cidr_id_2,
} = &contents; } = &contents;
// Verify an existing association doesn't currently exist
let existing_associations: usize = conn.query_row(
"SELECT COUNT(*)
FROM associations
WHERE (cidr_id_1 = ?1 AND cidr_id_2 = ?2) OR (cidr_id_1 = ?2 AND cidr_id_2 = ?1)",
params![cidr_id_1, cidr_id_2],
|r| r.get(0),
)?;
if existing_associations > 0 {
return Err(ServerError::InvalidQuery);
}
// Verify both provided CIDR IDs exist
let existing_cidrs: usize = conn.query_row(
"SELECT COUNT(*)
FROM cidrs
WHERE id = ?1 OR id = ?2",
params![cidr_id_1, cidr_id_2],
|r| r.get(0),
)?;
if existing_cidrs != 2 {
return Err(ServerError::InvalidQuery);
}
conn.execute( conn.execute(
"INSERT INTO associations (cidr_id_1, cidr_id_2) "INSERT INTO associations (cidr_id_1, cidr_id_2)
VALUES (?1, ?2)", VALUES (?1, ?2)",
@ -89,3 +113,103 @@ impl DatabaseAssociation {
Ok(auth_iter.collect::<Result<Vec<_>, rusqlite::Error>>()?) Ok(auth_iter.collect::<Result<Vec<_>, rusqlite::Error>>()?)
} }
} }
#[cfg(test)]
mod tests {
use crate::test;
use shared::{CidrContents, Error};
use super::*;
#[tokio::test]
async fn test_double_add() -> Result<(), Error> {
let server = test::Server::new()?;
let contents = AssociationContents {
cidr_id_1: 1,
cidr_id_2: 2,
};
let contents_flipped = AssociationContents {
cidr_id_1: 2,
cidr_id_2: 1,
};
let res = server
.form_request(
test::ADMIN_PEER_IP,
"POST",
"/v1/admin/associations",
&contents,
)
.await;
assert!(res.status().is_success());
let res = server
.form_request(
test::ADMIN_PEER_IP,
"POST",
"/v1/admin/associations",
&contents,
)
.await;
assert!(res.status().is_client_error());
let res = server
.form_request(
test::ADMIN_PEER_IP,
"POST",
"/v1/admin/associations",
&contents_flipped,
)
.await;
assert!(res.status().is_client_error());
Ok(())
}
#[tokio::test]
async fn test_nonexistent_cidr_id() -> Result<(), Error> {
let server = test::Server::new()?;
// Verify both provided CIDR IDs exist
let last_cidr_id: i64 =
server
.db()
.lock()
.query_row("SELECT COUNT(*) FROM cidrs", params![], |r| r.get(0))?;
let contents = AssociationContents {
cidr_id_1: 1,
cidr_id_2: last_cidr_id + 1,
};
let res = server
.form_request(
test::ADMIN_PEER_IP,
"POST",
"/v1/admin/associations",
&contents,
)
.await;
assert!(!res.status().is_success());
let cidr = CidrContents {
name: "experimental".to_string(),
cidr: test::EXPERIMENTAL_CIDR.parse()?,
parent: Some(test::ROOT_CIDR_ID),
};
let res = server
.form_request(test::ADMIN_PEER_IP, "POST", "/v1/admin/cidrs", &cidr)
.await;
assert!(res.status().is_success());
let res = server
.form_request(
test::ADMIN_PEER_IP,
"POST",
"/v1/admin/associations",
&contents,
)
.await;
assert!(res.status().is_success());
Ok(())
}
}