security upgrade

This commit is contained in:
Mateusz Gruszczyński
2026-07-30 09:57:43 +02:00
parent 2274cf57c9
commit f6b8e016a8
24 changed files with 1100 additions and 272 deletions
+33 -6
View File
@@ -18,16 +18,33 @@ pub struct AccessTokenRequest {
#[derive(Debug, Serialize)]
pub struct AccessTokenResponse {
access_token: String,
granted: bool,
expires_at: String,
}
pub async fn create_resource_access_token(
State(state): State<SharedState>,
headers: HeaderMap,
Json(payload): Json<AccessTokenRequest>,
) -> Result<Json<AccessTokenResponse>, ApiError> {
) -> Result<Response, ApiError> {
let kind = payload.kind.trim();
let slug = payload.slug.trim();
let client_key = crate::security::client_key(&headers);
let client_limit_key = format!("resource-password-client:{client_key}");
let limit_key = format!("resource-password:{client_key}:{kind}:{slug}");
let window = std::time::Duration::from_secs(15 * 60);
state
.check_rate_limit(client_limit_key, 50, window)
.await
.map_err(|seconds| ApiError::rate_limited(&format!(
"Too many password attempts. Try again in {seconds} seconds."
)))?;
state
.check_rate_limit(limit_key.clone(), 10, window)
.await
.map_err(|seconds| ApiError::rate_limited(&format!(
"Too many password attempts. Try again in {seconds} seconds."
)))?;
match kind {
"workspace" => {
let workspace = db::find_workspace(&state.db, slug)
@@ -63,10 +80,20 @@ pub async fn create_resource_access_token(
.bind(&expires_at)
.execute(state.db.pool())
.await?;
Ok(Json(AccessTokenResponse {
access_token: token,
state.clear_rate_limit(&limit_key).await;
let cookie = crate::security::resource_cookie(
kind,
slug,
&token,
state.anonymous_access_token_ttl_days,
);
let mut response = Json(AccessTokenResponse {
granted: true,
expires_at,
}))
})
.into_response();
response.headers_mut().insert(header::SET_COOKIE, cookie);
Ok(response)
}
pub async fn verify_resource_access_token(
@@ -78,7 +105,7 @@ pub async fn verify_resource_access_token(
let Some(token) = token.map(str::trim).filter(|value| !value.is_empty()) else {
return Ok(false);
};
if crate::auth::resource_permission(state, kind, slug, Some(token))
if crate::auth::share_link_permission(state, kind, slug, Some(token))
.await
.map_err(|error| ApiError::forbidden(&error.message))?
.is_some()