Skip to main content

rullst_orm/privacy/
sqlx_codec.rs

1//! SQLx column encoding of [`SecretString`]: values are encrypted on write and
2//! decrypted on read with the configured field-encryption key.
3
4use super::{SecretString, decrypt_configured_secret, encrypt_configured_secret};
5
6#[cfg(not(any(
7    feature = "strict-postgres",
8    feature = "strict-mysql",
9    feature = "strict-sqlite"
10)))]
11impl<'r> sqlx::Decode<'r, sqlx::Any> for SecretString {
12    fn decode(
13        value: sqlx::any::AnyValueRef<'r>,
14    ) -> Result<Self, Box<dyn std::error::Error + 'static + Send + Sync>> {
15        let text = <String as sqlx::Decode<sqlx::Any>>::decode(value)?;
16        let decrypted = decrypt_configured_secret(&text)?;
17        Ok(SecretString(decrypted))
18    }
19}
20
21#[cfg(not(any(
22    feature = "strict-postgres",
23    feature = "strict-mysql",
24    feature = "strict-sqlite"
25)))]
26impl<'q> sqlx::Encode<'q, sqlx::Any> for SecretString {
27    fn encode_by_ref(
28        &self,
29        buf: &mut <sqlx::Any as sqlx::database::Database>::ArgumentBuffer,
30    ) -> Result<sqlx::encode::IsNull, Box<dyn std::error::Error + Send + Sync>> {
31        let encrypted = encrypt_configured_secret(&self.0)?;
32        <String as sqlx::Encode<sqlx::Any>>::encode(encrypted, buf)
33    }
34}
35
36#[cfg(not(any(
37    feature = "strict-postgres",
38    feature = "strict-mysql",
39    feature = "strict-sqlite"
40)))]
41impl sqlx::Type<sqlx::Any> for SecretString {
42    fn type_info() -> sqlx::any::AnyTypeInfo {
43        <String as sqlx::Type<sqlx::Any>>::type_info()
44    }
45}
46
47// Support for strictly typed databases in Rullst
48#[cfg_attr(test, mutants::skip)]
49#[cfg(any(
50    feature = "strict-postgres",
51    feature = "strict-mysql",
52    feature = "strict-sqlite"
53))]
54impl<'r> sqlx::Decode<'r, crate::database::RullstDatabase> for SecretString {
55    fn decode(
56        value: <crate::database::RullstDatabase as sqlx::database::Database>::ValueRef<'r>,
57    ) -> Result<Self, Box<dyn std::error::Error + 'static + Send + Sync>> {
58        let text = <String as sqlx::Decode<crate::database::RullstDatabase>>::decode(value)?;
59        let decrypted = decrypt_configured_secret(&text)?;
60        Ok(SecretString(decrypted))
61    }
62}
63
64#[cfg_attr(test, mutants::skip)]
65#[cfg(any(
66    feature = "strict-postgres",
67    feature = "strict-mysql",
68    feature = "strict-sqlite"
69))]
70impl<'q> sqlx::Encode<'q, crate::database::RullstDatabase> for SecretString {
71    fn encode_by_ref(
72        &self,
73        buf: &mut <crate::database::RullstDatabase as sqlx::database::Database>::ArgumentBuffer,
74    ) -> Result<sqlx::encode::IsNull, Box<dyn std::error::Error + Send + Sync>> {
75        let encrypted = encrypt_configured_secret(&self.0)?;
76        <String as sqlx::Encode<crate::database::RullstDatabase>>::encode(encrypted, buf)
77    }
78}
79
80#[cfg_attr(test, mutants::skip)]
81#[cfg(any(
82    feature = "strict-postgres",
83    feature = "strict-mysql",
84    feature = "strict-sqlite"
85))]
86impl sqlx::Type<crate::database::RullstDatabase> for SecretString {
87    fn type_info() -> <crate::database::RullstDatabase as sqlx::database::Database>::TypeInfo {
88        <String as sqlx::Type<crate::database::RullstDatabase>>::type_info()
89    }
90}