Use integer IDs for files
This commit is contained in:
parent
7ee9714846
commit
9d6c7f8566
|
@ -1323,7 +1323,6 @@ dependencies = [
|
|||
"tokio",
|
||||
"tokio-test",
|
||||
"url",
|
||||
"uuid",
|
||||
"warp",
|
||||
"x25519-dalek",
|
||||
]
|
||||
|
@ -1754,15 +1753,6 @@ version = "0.7.5"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "05e42f7c18b8f902290b009cde6d651262f956c98bc51bca4cd1d511c9cd85c7"
|
||||
|
||||
[[package]]
|
||||
name = "uuid"
|
||||
version = "0.8.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bc5cf98d8186244414c848017f0e2676b3fcb46807f6668a97dfe67359a3c4b7"
|
||||
dependencies = [
|
||||
"getrandom 0.2.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "vcpkg"
|
||||
version = "0.2.11"
|
||||
|
|
|
@ -25,7 +25,6 @@ sha2 = "0.9"
|
|||
structopt = "0.3"
|
||||
tokio = { version = "1.3", features = ["full"] }
|
||||
url = "2.2.1"
|
||||
uuid = { version = "0.8", features = ["v4"] }
|
||||
warp = { version = "0.3", features = ["tls"] }
|
||||
x25519-dalek = "1.1"
|
||||
|
||||
|
|
|
@ -8,7 +8,6 @@ use chrono;
|
|||
use rand::{thread_rng, Rng};
|
||||
use rusqlite::params;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use uuid::Uuid;
|
||||
use warp::{http::StatusCode, reply::Reply, reply::Response, Rejection};
|
||||
|
||||
use super::crypto;
|
||||
|
@ -112,6 +111,8 @@ pub async fn get_all_rooms() -> Result<Response, Rejection> {
|
|||
pub async fn store_file(
|
||||
base64_encoded_bytes: &str, auth_token: &str, pool: &storage::DatabaseConnectionPool,
|
||||
) -> Result<Response, Rejection> {
|
||||
// It'd be nice to use the UUID crate for the file ID, but clients want an integer ID
|
||||
let now = chrono::Utc::now().timestamp();
|
||||
// Check authorization level
|
||||
let (has_authorization_level, _) =
|
||||
has_authorization_level(auth_token, AuthorizationLevel::Basic, pool).await?;
|
||||
|
@ -126,17 +127,12 @@ pub async fn store_file(
|
|||
return Err(warp::reject::custom(Error::ValidationFailed));
|
||||
}
|
||||
};
|
||||
// Generate UUID
|
||||
let id = Uuid::new_v4();
|
||||
let mut buffer = Uuid::encode_buffer();
|
||||
let id: String = id.to_simple().encode_lower(&mut buffer).to_string();
|
||||
// Update the database
|
||||
// We do this * before * storing the actual file, so that in case something goes
|
||||
// wrong we're not left with files that'll never be pruned.
|
||||
let now = chrono::Utc::now().timestamp();
|
||||
let conn = pool.get().map_err(|_| Error::DatabaseFailedInternally)?;
|
||||
let stmt = format!("INSERT INTO {} (id, timestamp) VALUES (?1, ?2)", storage::FILES_TABLE);
|
||||
let _ = match conn.execute(&stmt, params![id, now]) {
|
||||
let _ = match conn.execute(&stmt, params![now, now]) {
|
||||
Ok(rows) => rows,
|
||||
Err(e) => {
|
||||
println!("Couldn't insert file record due to error: {}.", e);
|
||||
|
@ -145,7 +141,7 @@ pub async fn store_file(
|
|||
};
|
||||
// Write to file
|
||||
let mut pos = 0;
|
||||
let raw_path = format!("files/{}", &id);
|
||||
let raw_path = format!("files/{}", &now);
|
||||
let path = Path::new(&raw_path);
|
||||
let mut buffer = match fs::File::create(path) {
|
||||
Ok(buffer) => buffer,
|
||||
|
@ -165,12 +161,17 @@ pub async fn store_file(
|
|||
pos += count;
|
||||
}
|
||||
// Return
|
||||
let json = GenericStringResponse { status_code: StatusCode::OK.as_u16(), result: id };
|
||||
return Ok(warp::reply::json(&json).into_response());
|
||||
#[derive(Debug, Deserialize, Serialize)]
|
||||
struct Response {
|
||||
status_code: u16,
|
||||
result: i64,
|
||||
}
|
||||
let response = Response { status_code: StatusCode::OK.as_u16(), result: now };
|
||||
return Ok(warp::reply::json(&response).into_response());
|
||||
}
|
||||
|
||||
pub async fn get_file(
|
||||
id: &str, auth_token: &str, pool: &storage::DatabaseConnectionPool,
|
||||
id: i64, auth_token: &str, pool: &storage::DatabaseConnectionPool,
|
||||
) -> Result<GenericStringResponse, Rejection> {
|
||||
// Doesn't return a response directly for testing purposes
|
||||
// Check authorization level
|
||||
|
@ -179,14 +180,6 @@ pub async fn get_file(
|
|||
if !has_authorization_level {
|
||||
return Err(warp::reject::custom(Error::Unauthorized));
|
||||
}
|
||||
// Check that the ID is a valid UUID
|
||||
match Uuid::parse_str(id) {
|
||||
Ok(_) => (),
|
||||
Err(e) => {
|
||||
println!("Couldn't parse UUID from: {} due to error: {}.", id, e);
|
||||
return Err(warp::reject::custom(Error::ValidationFailed));
|
||||
}
|
||||
};
|
||||
// Try to read the file
|
||||
let raw_path = format!("files/{}", id);
|
||||
let path = Path::new(&raw_path);
|
||||
|
|
|
@ -94,7 +94,13 @@ async fn handle_get_request(
|
|||
println!("Invalid endpoint: {}.", rpc_call.endpoint);
|
||||
return Err(warp::reject::custom(Error::InvalidRpcCall));
|
||||
}
|
||||
let file_id = components[1];
|
||||
let file_id: i64 = match components[1].parse() {
|
||||
Ok(file_id) => file_id,
|
||||
Err(_) => {
|
||||
println!("Invalid endpoint: {}.", rpc_call.endpoint);
|
||||
return Err(warp::reject::custom(Error::InvalidRpcCall));
|
||||
}
|
||||
};
|
||||
return handlers::get_file(file_id, &auth_token, &pool)
|
||||
.await
|
||||
.map(|json| warp::reply::json(&json).into_response());
|
||||
|
|
|
@ -147,7 +147,7 @@ fn create_room_tables_if_needed(conn: &DatabaseConnection) {
|
|||
// Files
|
||||
let files_table_cmd = format!(
|
||||
"CREATE TABLE IF NOT EXISTS {} (
|
||||
id STRING PRIMARY KEY,
|
||||
id INTEGER PRIMARY KEY,
|
||||
timestamp INTEGER
|
||||
)",
|
||||
FILES_TABLE
|
||||
|
@ -261,10 +261,10 @@ pub async fn prune_files(file_expiration: i64) {
|
|||
return println!("Couldn't prune files due to error: {}.", e);
|
||||
}
|
||||
};
|
||||
let ids: Vec<String> = rows.filter_map(|result| result.ok()).collect();
|
||||
let ids: Vec<i64> = rows.filter_map(|result| result.ok()).collect();
|
||||
if !ids.is_empty() {
|
||||
// Delete the files
|
||||
let mut deleted_ids: Vec<String> = vec![];
|
||||
let mut deleted_ids: Vec<i64> = vec![];
|
||||
for id in ids {
|
||||
match fs::remove_file(format!("files/{}", id)) {
|
||||
Ok(_) => deleted_ids.push(id),
|
||||
|
|
|
@ -90,9 +90,9 @@ fn test_file_handling() {
|
|||
// Check that there's a file record
|
||||
let conn = pool.get().unwrap();
|
||||
let raw_query = format!("SELECT id FROM {}", storage::FILES_TABLE);
|
||||
let id: String = conn.query_row(&raw_query, params![], |row| Ok(row.get(0)?)).unwrap();
|
||||
let id: i64 = conn.query_row(&raw_query, params![], |row| Ok(row.get(0)?)).unwrap();
|
||||
// Retrieve the file and check the content
|
||||
let base64_encoded_file = aw!(handlers::get_file(&id, &auth_token, &pool)).unwrap().result;
|
||||
let base64_encoded_file = aw!(handlers::get_file(id, &auth_token, &pool)).unwrap().result;
|
||||
assert_eq!(base64_encoded_file, TEST_FILE);
|
||||
// Prune the file and check that it's gone
|
||||
aw!(storage::prune_files(-60)); // Will evaluate to now + 60
|
||||
|
|
Loading…
Reference in New Issue