fixes and functions

This commit is contained in:
Mateusz Gruszczyński committed 2026-08-05 23:52:41 +02:00
1 parent 4643de4309
commit a7329f5535
13 files changed
+330 -15

No files matched your search

+36 -1
View File
@@ -22,6 +22,9 @@ pub const CSRF_HEADER: &str = "x-rustpad-csrf";
const CSRF_TOKEN_BYTES: usize = 32;
const CSRF_TTL_SECONDS: i64 = 24 * 60 * 60;
const RESOURCE_ACCESS_COOKIE_PREFIX: &str = "__Host-rustpad_access_";
const RESOURCE_ACCESS_COOKIE_SUFFIX_LENGTH: usize = 24;
const RESOURCE_ACCESS_TOKEN_LENGTH: usize = 64;
#[derive(Serialize)]
pub struct CsrfResponse {
@@ -50,6 +53,26 @@ pub fn resource_token<'a>(headers: &'a HeaderMap, kind: &str, slug: &str) -> Opt
cookie_value(headers, &name)
}
pub(crate) fn resource_access_cookies(headers: &HeaderMap) -> Vec<(String, Option<String>)> {
headers
.get_all(header::COOKIE)
.iter()
.filter_map(|value| value.to_str().ok())
.flat_map(|cookies| cookies.split(';'))
.filter_map(|part| {
let (name, value) = part.trim().split_once('=')?;
if !valid_resource_access_cookie_name(name) {
return None;
}
let value = value.trim();
let token = (value.len() == RESOURCE_ACCESS_TOKEN_LENGTH
&& value.bytes().all(|byte| byte.is_ascii_hexdigit()))
.then(|| value.to_owned());
Some((name.to_owned(), token))
})
.collect()
}
pub fn share_session_token<'a>(headers: &'a HeaderMap, kind: &str, slug: &str) -> Option<&'a str> {
let name = share_session_cookie_name(kind, slug);
cookie_value(headers, &name)
@@ -63,6 +86,10 @@ pub fn clear_session_cookie() -> HeaderValue {
clear_cookie(SESSION_COOKIE)
}
pub(crate) fn clear_resource_access_cookie(name: &str) -> Option<HeaderValue> {
valid_resource_access_cookie_name(name).then(|| clear_cookie(name))
}
pub async fn csrf_token_endpoint(headers: HeaderMap) -> Response {
let token = csrf_cookie_token(&headers)
.filter(|value| valid_csrf_token(value))
@@ -176,7 +203,15 @@ pub fn websocket_origin_allowed(headers: &HeaderMap) -> bool {
fn resource_cookie_name(kind: &str, slug: &str) -> String {
let digest = Sha256::digest(format!("{kind}:{slug}").as_bytes());
format!("__Host-rustpad_access_{}", hex::encode(&digest[..12]))
format!("{RESOURCE_ACCESS_COOKIE_PREFIX}{}", hex::encode(&digest[..12]))
}
fn valid_resource_access_cookie_name(name: &str) -> bool {
name.strip_prefix(RESOURCE_ACCESS_COOKIE_PREFIX)
.is_some_and(|suffix| {
suffix.len() == RESOURCE_ACCESS_COOKIE_SUFFIX_LENGTH
&& suffix.bytes().all(|byte| byte.is_ascii_hexdigit())
})
}
fn share_session_cookie_name(kind: &str, slug: &str) -> String {