release: secrets-mcp 0.5.2
Some checks failed
Secrets MCP — Build & Release / 检查 / 构建 / 发版 (push) Successful in 6m7s
Secrets MCP — Build & Release / 部署 secrets-mcp (push) Failing after 6s

Bump version: secrets-mcp-0.5.1 tag already existed while crates had further changes.

Made-with: Cursor
This commit is contained in:
2026-04-05 10:38:50 +08:00
parent aefad33870
commit dd24f7cc44
15 changed files with 787 additions and 66 deletions

View File

@@ -2,6 +2,8 @@ use anyhow::Result;
use sqlx::PgPool;
use uuid::Uuid;
use crate::error::AppError;
const KEY_PREFIX: &str = "sk_";
/// Generate a new API key: `sk_<64 hex chars>` = 67 characters total.
@@ -14,23 +16,32 @@ pub fn generate_api_key() -> String {
}
/// Return the user's existing API key, or generate and store a new one if NULL.
/// Uses a transaction with atomic update to prevent TOCTOU race conditions.
pub async fn ensure_api_key(pool: &PgPool, user_id: Uuid) -> Result<String> {
let existing: Option<(Option<String>,)> =
sqlx::query_as("SELECT api_key FROM users WHERE id = $1")
.bind(user_id)
.fetch_optional(pool)
.await?;
let mut tx = pool.begin().await?;
if let Some((Some(key),)) = existing {
// Lock the row and check existing key
let existing: (Option<String>,) =
sqlx::query_as("SELECT api_key FROM users WHERE id = $1 FOR UPDATE")
.bind(user_id)
.fetch_optional(&mut *tx)
.await?
.ok_or(AppError::NotFoundUser)?;
if let Some(key) = existing.0 {
tx.commit().await?;
return Ok(key);
}
// Generate and store new key atomically
let new_key = generate_api_key();
sqlx::query("UPDATE users SET api_key = $1 WHERE id = $2")
.bind(&new_key)
.bind(user_id)
.execute(pool)
.execute(&mut *tx)
.await?;
tx.commit().await?;
Ok(new_key)
}