Skip to main content

usenet_dl/db/
passwords.rs

1//! Password cache operations for archive extraction.
2
3use crate::error::DatabaseError;
4use crate::types::DownloadId;
5use crate::{Error, Result};
6
7use super::Database;
8
9impl Database {
10    /// Cache a correct password for a download
11    ///
12    /// This is used after successfully extracting an archive with a password,
13    /// so if the download needs to be reprocessed, we can try this password first.
14    pub async fn set_correct_password(
15        &self,
16        download_id: DownloadId,
17        password: &str,
18    ) -> Result<()> {
19        sqlx::query(
20            r#"
21            INSERT INTO passwords (download_id, correct_password)
22            VALUES (?, ?)
23            ON CONFLICT(download_id) DO UPDATE SET correct_password = excluded.correct_password
24            "#,
25        )
26        .bind(download_id)
27        .bind(password)
28        .execute(&self.pool)
29        .await
30        .map_err(|e| {
31            Error::Database(DatabaseError::QueryFailed(format!(
32                "Failed to set correct password: {}",
33                e
34            )))
35        })?;
36
37        Ok(())
38    }
39
40    /// Get the cached correct password for a download
41    ///
42    /// Returns None if no password is cached for this download.
43    pub async fn get_cached_password(&self, download_id: DownloadId) -> Result<Option<String>> {
44        let password: Option<String> =
45            sqlx::query_scalar("SELECT correct_password FROM passwords WHERE download_id = ?")
46                .bind(download_id)
47                .fetch_optional(&self.pool)
48                .await
49                .map_err(|e| {
50                    Error::Database(DatabaseError::QueryFailed(format!(
51                        "Failed to get cached password: {}",
52                        e
53                    )))
54                })?;
55
56        Ok(password)
57    }
58
59    /// Delete cached password for a download
60    ///
61    /// Note: This is automatically deleted via CASCADE when the download is deleted.
62    pub async fn delete_cached_password(&self, download_id: DownloadId) -> Result<()> {
63        sqlx::query("DELETE FROM passwords WHERE download_id = ?")
64            .bind(download_id)
65            .execute(&self.pool)
66            .await
67            .map_err(|e| {
68                Error::Database(DatabaseError::QueryFailed(format!(
69                    "Failed to delete cached password: {}",
70                    e
71                )))
72            })?;
73
74        Ok(())
75    }
76}