geforkt von mirrored/vaultwarden
Add token with short expiration time to send url
Dieser Commit ist enthalten in:
Ursprung
f44b2611e6
Commit
2cd17fe7af
3 geänderte Dateien mit 52 neuen und 43 gelöschten Zeilen
|
@ -2,7 +2,7 @@ use std::{io::Read, path::Path};
|
||||||
|
|
||||||
use chrono::{DateTime, Duration, Utc};
|
use chrono::{DateTime, Duration, Utc};
|
||||||
use multipart::server::{save::SavedData, Multipart, SaveResult};
|
use multipart::server::{save::SavedData, Multipart, SaveResult};
|
||||||
use rocket::{http::ContentType, Data};
|
use rocket::{http::ContentType, response::NamedFile, Data};
|
||||||
use rocket_contrib::json::Json;
|
use rocket_contrib::json::Json;
|
||||||
use serde_json::Value;
|
use serde_json::Value;
|
||||||
|
|
||||||
|
@ -16,7 +16,16 @@ use crate::{
|
||||||
const SEND_INACCESSIBLE_MSG: &str = "Send does not exist or is no longer available";
|
const SEND_INACCESSIBLE_MSG: &str = "Send does not exist or is no longer available";
|
||||||
|
|
||||||
pub fn routes() -> Vec<rocket::Route> {
|
pub fn routes() -> Vec<rocket::Route> {
|
||||||
routes![post_send, post_send_file, post_access, post_access_file, put_send, delete_send, put_remove_password]
|
routes![
|
||||||
|
post_send,
|
||||||
|
post_send_file,
|
||||||
|
post_access,
|
||||||
|
post_access_file,
|
||||||
|
put_send,
|
||||||
|
delete_send,
|
||||||
|
put_remove_password,
|
||||||
|
download_send
|
||||||
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn purge_sends(pool: DbPool) {
|
pub fn purge_sends(pool: DbPool) {
|
||||||
|
@ -316,13 +325,25 @@ fn post_access_file(
|
||||||
|
|
||||||
send.save(&conn)?;
|
send.save(&conn)?;
|
||||||
|
|
||||||
|
let token_claims = crate::auth::generate_send_claims(&send_id, &file_id);
|
||||||
|
let token = crate::auth::encode_jwt(&token_claims);
|
||||||
Ok(Json(json!({
|
Ok(Json(json!({
|
||||||
"Object": "send-fileDownload",
|
"Object": "send-fileDownload",
|
||||||
"Id": file_id,
|
"Id": file_id,
|
||||||
"Url": format!("{}/sends/{}/{}", &host.host, send_id, file_id)
|
"Url": format!("{}/api/sends/{}/{}?t={}", &host.host, send_id, file_id, token)
|
||||||
})))
|
})))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[get("/sends/<send_id>/<file_id>?<t>")]
|
||||||
|
fn download_send(send_id: String, file_id: String, t: String) -> Option<NamedFile> {
|
||||||
|
if let Ok(claims) = crate::auth::decode_send(&t) {
|
||||||
|
if claims.sub == format!("{}/{}", send_id, file_id) {
|
||||||
|
return NamedFile::open(Path::new(&CONFIG.sends_folder()).join(send_id).join(file_id)).ok();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
#[put("/sends/<id>", data = "<data>")]
|
#[put("/sends/<id>", data = "<data>")]
|
||||||
fn put_send(id: String, data: JsonUpcase<SendData>, headers: Headers, conn: DbConn, nt: Notify) -> JsonResult {
|
fn put_send(id: String, data: JsonUpcase<SendData>, headers: Headers, conn: DbConn, nt: Notify) -> JsonResult {
|
||||||
enforce_disable_send_policy(&headers, &conn)?;
|
enforce_disable_send_policy(&headers, &conn)?;
|
||||||
|
|
|
@ -10,7 +10,7 @@ pub fn routes() -> Vec<Route> {
|
||||||
// If addding more routes here, consider also adding them to
|
// If addding more routes here, consider also adding them to
|
||||||
// crate::utils::LOGGED_ROUTES to make sure they appear in the log
|
// crate::utils::LOGGED_ROUTES to make sure they appear in the log
|
||||||
if CONFIG.web_vault_enabled() {
|
if CONFIG.web_vault_enabled() {
|
||||||
routes![web_index, app_id, web_files, attachments, sends, alive, static_files]
|
routes![web_index, app_id, web_files, attachments, alive, static_files]
|
||||||
} else {
|
} else {
|
||||||
routes![attachments, alive, static_files]
|
routes![attachments, alive, static_files]
|
||||||
}
|
}
|
||||||
|
@ -60,11 +60,6 @@ fn attachments(uuid: String, file_id: String) -> Option<NamedFile> {
|
||||||
NamedFile::open(Path::new(&CONFIG.attachments_folder()).join(uuid).join(file_id)).ok()
|
NamedFile::open(Path::new(&CONFIG.attachments_folder()).join(uuid).join(file_id)).ok()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[get("/sends/<send_id>/<file_id>")]
|
|
||||||
fn sends(send_id: String, file_id: String) -> Option<NamedFile> {
|
|
||||||
NamedFile::open(Path::new(&CONFIG.sends_folder()).join(send_id).join(file_id)).ok()
|
|
||||||
}
|
|
||||||
|
|
||||||
#[get("/alive")]
|
#[get("/alive")]
|
||||||
fn alive() -> Json<String> {
|
fn alive() -> Json<String> {
|
||||||
use crate::util::format_date;
|
use crate::util::format_date;
|
||||||
|
|
61
src/auth.rs
61
src/auth.rs
|
@ -19,11 +19,14 @@ const JWT_ALGORITHM: Algorithm = Algorithm::RS256;
|
||||||
|
|
||||||
pub static DEFAULT_VALIDITY: Lazy<Duration> = Lazy::new(|| Duration::hours(2));
|
pub static DEFAULT_VALIDITY: Lazy<Duration> = Lazy::new(|| Duration::hours(2));
|
||||||
static JWT_HEADER: Lazy<Header> = Lazy::new(|| Header::new(JWT_ALGORITHM));
|
static JWT_HEADER: Lazy<Header> = Lazy::new(|| Header::new(JWT_ALGORITHM));
|
||||||
|
|
||||||
pub static JWT_LOGIN_ISSUER: Lazy<String> = Lazy::new(|| format!("{}|login", CONFIG.domain_origin()));
|
pub static JWT_LOGIN_ISSUER: Lazy<String> = Lazy::new(|| format!("{}|login", CONFIG.domain_origin()));
|
||||||
static JWT_INVITE_ISSUER: Lazy<String> = Lazy::new(|| format!("{}|invite", CONFIG.domain_origin()));
|
static JWT_INVITE_ISSUER: Lazy<String> = Lazy::new(|| format!("{}|invite", CONFIG.domain_origin()));
|
||||||
static JWT_DELETE_ISSUER: Lazy<String> = Lazy::new(|| format!("{}|delete", CONFIG.domain_origin()));
|
static JWT_DELETE_ISSUER: Lazy<String> = Lazy::new(|| format!("{}|delete", CONFIG.domain_origin()));
|
||||||
static JWT_VERIFYEMAIL_ISSUER: Lazy<String> = Lazy::new(|| format!("{}|verifyemail", CONFIG.domain_origin()));
|
static JWT_VERIFYEMAIL_ISSUER: Lazy<String> = Lazy::new(|| format!("{}|verifyemail", CONFIG.domain_origin()));
|
||||||
static JWT_ADMIN_ISSUER: Lazy<String> = Lazy::new(|| format!("{}|admin", CONFIG.domain_origin()));
|
static JWT_ADMIN_ISSUER: Lazy<String> = Lazy::new(|| format!("{}|admin", CONFIG.domain_origin()));
|
||||||
|
static JWT_SEND_ISSUER: Lazy<String> = Lazy::new(|| format!("{}|send", CONFIG.domain_origin()));
|
||||||
|
|
||||||
static PRIVATE_RSA_KEY: Lazy<Vec<u8>> = Lazy::new(|| match read_file(&CONFIG.private_rsa_key()) {
|
static PRIVATE_RSA_KEY: Lazy<Vec<u8>> = Lazy::new(|| match read_file(&CONFIG.private_rsa_key()) {
|
||||||
Ok(key) => key,
|
Ok(key) => key,
|
||||||
Err(e) => panic!("Error loading private RSA Key.\n Error: {}", e),
|
Err(e) => panic!("Error loading private RSA Key.\n Error: {}", e),
|
||||||
|
@ -66,18 +69,22 @@ pub fn decode_invite(token: &str) -> Result<InviteJwtClaims, Error> {
|
||||||
decode_jwt(token, JWT_INVITE_ISSUER.to_string())
|
decode_jwt(token, JWT_INVITE_ISSUER.to_string())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn decode_delete(token: &str) -> Result<DeleteJwtClaims, Error> {
|
pub fn decode_delete(token: &str) -> Result<BasicJwtClaims, Error> {
|
||||||
decode_jwt(token, JWT_DELETE_ISSUER.to_string())
|
decode_jwt(token, JWT_DELETE_ISSUER.to_string())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn decode_verify_email(token: &str) -> Result<VerifyEmailJwtClaims, Error> {
|
pub fn decode_verify_email(token: &str) -> Result<BasicJwtClaims, Error> {
|
||||||
decode_jwt(token, JWT_VERIFYEMAIL_ISSUER.to_string())
|
decode_jwt(token, JWT_VERIFYEMAIL_ISSUER.to_string())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn decode_admin(token: &str) -> Result<AdminJwtClaims, Error> {
|
pub fn decode_admin(token: &str) -> Result<BasicJwtClaims, Error> {
|
||||||
decode_jwt(token, JWT_ADMIN_ISSUER.to_string())
|
decode_jwt(token, JWT_ADMIN_ISSUER.to_string())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn decode_send(token: &str) -> Result<BasicJwtClaims, Error> {
|
||||||
|
decode_jwt(token, JWT_SEND_ISSUER.to_string())
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize)]
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
pub struct LoginJwtClaims {
|
pub struct LoginJwtClaims {
|
||||||
// Not before
|
// Not before
|
||||||
|
@ -147,7 +154,7 @@ pub fn generate_invite_claims(
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize)]
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
pub struct DeleteJwtClaims {
|
pub struct BasicJwtClaims {
|
||||||
// Not before
|
// Not before
|
||||||
pub nbf: i64,
|
pub nbf: i64,
|
||||||
// Expiration time
|
// Expiration time
|
||||||
|
@ -158,9 +165,9 @@ pub struct DeleteJwtClaims {
|
||||||
pub sub: String,
|
pub sub: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn generate_delete_claims(uuid: String) -> DeleteJwtClaims {
|
pub fn generate_delete_claims(uuid: String) -> BasicJwtClaims {
|
||||||
let time_now = Utc::now().naive_utc();
|
let time_now = Utc::now().naive_utc();
|
||||||
DeleteJwtClaims {
|
BasicJwtClaims {
|
||||||
nbf: time_now.timestamp(),
|
nbf: time_now.timestamp(),
|
||||||
exp: (time_now + Duration::days(5)).timestamp(),
|
exp: (time_now + Duration::days(5)).timestamp(),
|
||||||
iss: JWT_DELETE_ISSUER.to_string(),
|
iss: JWT_DELETE_ISSUER.to_string(),
|
||||||
|
@ -168,21 +175,9 @@ pub fn generate_delete_claims(uuid: String) -> DeleteJwtClaims {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize)]
|
pub fn generate_verify_email_claims(uuid: String) -> BasicJwtClaims {
|
||||||
pub struct VerifyEmailJwtClaims {
|
|
||||||
// Not before
|
|
||||||
pub nbf: i64,
|
|
||||||
// Expiration time
|
|
||||||
pub exp: i64,
|
|
||||||
// Issuer
|
|
||||||
pub iss: String,
|
|
||||||
// Subject
|
|
||||||
pub sub: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn generate_verify_email_claims(uuid: String) -> DeleteJwtClaims {
|
|
||||||
let time_now = Utc::now().naive_utc();
|
let time_now = Utc::now().naive_utc();
|
||||||
DeleteJwtClaims {
|
BasicJwtClaims {
|
||||||
nbf: time_now.timestamp(),
|
nbf: time_now.timestamp(),
|
||||||
exp: (time_now + Duration::days(5)).timestamp(),
|
exp: (time_now + Duration::days(5)).timestamp(),
|
||||||
iss: JWT_VERIFYEMAIL_ISSUER.to_string(),
|
iss: JWT_VERIFYEMAIL_ISSUER.to_string(),
|
||||||
|
@ -190,21 +185,9 @@ pub fn generate_verify_email_claims(uuid: String) -> DeleteJwtClaims {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize)]
|
pub fn generate_admin_claims() -> BasicJwtClaims {
|
||||||
pub struct AdminJwtClaims {
|
|
||||||
// Not before
|
|
||||||
pub nbf: i64,
|
|
||||||
// Expiration time
|
|
||||||
pub exp: i64,
|
|
||||||
// Issuer
|
|
||||||
pub iss: String,
|
|
||||||
// Subject
|
|
||||||
pub sub: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn generate_admin_claims() -> AdminJwtClaims {
|
|
||||||
let time_now = Utc::now().naive_utc();
|
let time_now = Utc::now().naive_utc();
|
||||||
AdminJwtClaims {
|
BasicJwtClaims {
|
||||||
nbf: time_now.timestamp(),
|
nbf: time_now.timestamp(),
|
||||||
exp: (time_now + Duration::minutes(20)).timestamp(),
|
exp: (time_now + Duration::minutes(20)).timestamp(),
|
||||||
iss: JWT_ADMIN_ISSUER.to_string(),
|
iss: JWT_ADMIN_ISSUER.to_string(),
|
||||||
|
@ -212,6 +195,16 @@ pub fn generate_admin_claims() -> AdminJwtClaims {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn generate_send_claims(send_id: &str, file_id: &str) -> BasicJwtClaims {
|
||||||
|
let time_now = Utc::now().naive_utc();
|
||||||
|
BasicJwtClaims {
|
||||||
|
nbf: time_now.timestamp(),
|
||||||
|
exp: (time_now + Duration::minutes(2)).timestamp(),
|
||||||
|
iss: JWT_SEND_ISSUER.to_string(),
|
||||||
|
sub: format!("{}/{}", send_id, file_id),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// Bearer token authentication
|
// Bearer token authentication
|
||||||
//
|
//
|
||||||
|
|
Laden …
In neuem Issue referenzieren