Browse Source

Fix local attachment download endpoint

pull/7298/head
Puneet Dixit 1 week ago
parent
commit
95d2a73671
  1. 22
      src/api/core/ciphers.rs
  2. 19
      src/db/models/attachment.rs

22
src/api/core/ciphers.rs

@ -1,11 +1,14 @@
use std::collections::{HashMap, HashSet};
use std::{
collections::{HashMap, HashSet},
path::Path,
};
use chrono::{NaiveDateTime, Utc};
use num_traits::ToPrimitive;
use rocket::{
Route,
form::{Form, FromForm},
fs::TempFile,
fs::{NamedFile, TempFile},
serde::json::Json,
};
use serde_json::Value;
@ -13,7 +16,7 @@ use serde_json::Value;
use crate::{
CONFIG,
api::{self, EmptyResult, JsonResult, Notify, PasswordOrOtpData, UpdateType, core::log_event},
auth::ClientVersion,
auth::{ClientVersion, decode_file_download},
auth::{Headers, OrgIdGuard, OwnerHeaders},
config::PathType,
crypto,
@ -53,6 +56,7 @@ pub fn routes() -> Vec<Route> {
post_ciphers_create,
post_ciphers_import,
get_attachment,
download_attachment,
post_attachment_v2,
post_attachment_v2_data,
post_attachment, // legacy
@ -1104,6 +1108,18 @@ async fn get_attachment(
}
}
/// Serves a locally stored attachment file using a time-limited, signed token.
#[get("/ciphers/attachment/download?<token>")]
async fn download_attachment(token: String) -> Option<NamedFile> {
let Ok(claims) = decode_file_download(&token) else {
return None;
};
NamedFile::open(Path::new(&CONFIG.attachments_folder()).join(claims.sub.as_ref()).join(claims.file_id.as_ref()))
.await
.ok()
}
#[derive(Deserialize)]
#[serde(rename_all = "camelCase")]
struct AttachmentRequestData {

19
src/db/models/attachment.rs

@ -59,7 +59,7 @@ impl Attachment {
if crate::storage::is_fs_operator(&operator) {
let token = encode_jwt(&generate_file_download_claims(self.cipher_uuid.clone(), self.id.clone()));
Ok(format!("{host}/attachments/{}/{}?token={token}", self.cipher_uuid, self.id))
Ok(attachment_download_url(host, &token))
} else {
Ok(operator.presign_read(&self.get_file_path(), Duration::from_mins(5)).await?.uri().to_string())
}
@ -78,6 +78,23 @@ impl Attachment {
}
}
fn attachment_download_url(host: &str, token: &str) -> String {
format!("{host}/api/ciphers/attachment/download?token={token}")
}
#[cfg(test)]
mod tests {
use super::attachment_download_url;
#[test]
fn attachment_download_url_uses_api_endpoint() {
assert_eq!(
attachment_download_url("https://vault.example", "download.token"),
"https://vault.example/api/ciphers/attachment/download?token=download.token"
);
}
}
/// Database methods
impl Attachment {
pub async fn save(&self, conn: &DbConn) -> EmptyResult {

Loading…
Cancel
Save