@@ -184,18 +184,70 @@ impl KeyConfig {
184184 }
185185}
186186
187- /// Application secrets
187+ /// Encryption config option.
188+ #[ derive( Debug , Clone ) ]
189+ pub enum Encryption {
190+ File ( Utf8PathBuf ) ,
191+ Value ( [ u8 ; 32 ] ) ,
192+ }
193+
194+ /// Encryption fields as serialized in JSON.
188195#[ serde_as]
189- #[ derive( Debug , Clone , Serialize , Deserialize , JsonSchema ) ]
190- pub struct SecretsConfig {
191- /// Encryption key for secure cookies
196+ #[ derive( JsonSchema , Serialize , Deserialize , Debug , Clone ) ]
197+ struct EncryptionRaw {
198+ /// File containing the encryption key for secure cookies.
199+ #[ schemars( with = "Option<String>" ) ]
200+ #[ serde( skip_serializing_if = "Option::is_none" ) ]
201+ encryption_file : Option < Utf8PathBuf > ,
202+
203+ /// Encryption key for secure cookies.
192204 #[ schemars(
193- with = "String" ,
205+ with = "Option< String> " ,
194206 regex( pattern = r"[0-9a-fA-F]{64}" ) ,
195207 example = "example_secret"
196208 ) ]
197- #[ serde_as( as = "serde_with::hex::Hex" ) ]
198- pub encryption : [ u8 ; 32 ] ,
209+ #[ serde_as( as = "Option<serde_with::hex::Hex>" ) ]
210+ #[ serde( skip_serializing_if = "Option::is_none" ) ]
211+ encryption : Option < [ u8 ; 32 ] > ,
212+ }
213+
214+ impl TryFrom < EncryptionRaw > for Encryption {
215+ type Error = anyhow:: Error ;
216+
217+ fn try_from ( value : EncryptionRaw ) -> Result < Encryption , Self :: Error > {
218+ match ( value. encryption , value. encryption_file ) {
219+ ( None , None ) => bail ! ( "Missing `encryption` or `encryption_file`" ) ,
220+ ( None , Some ( path) ) => Ok ( Encryption :: File ( path) ) ,
221+ ( Some ( encryption) , None ) => Ok ( Encryption :: Value ( encryption) ) ,
222+ ( Some ( _) , Some ( _) ) => bail ! ( "Cannot specify both `encryption` and `encryption_file`" ) ,
223+ }
224+ }
225+ }
226+
227+ impl From < Encryption > for EncryptionRaw {
228+ fn from ( value : Encryption ) -> Self {
229+ match value {
230+ Encryption :: File ( path) => EncryptionRaw {
231+ encryption_file : Some ( path) ,
232+ encryption : None ,
233+ } ,
234+ Encryption :: Value ( encryption) => EncryptionRaw {
235+ encryption_file : None ,
236+ encryption : Some ( encryption) ,
237+ } ,
238+ }
239+ }
240+ }
241+
242+ /// Application secrets
243+ #[ serde_as]
244+ #[ derive( Debug , Clone , Serialize , Deserialize , JsonSchema ) ]
245+ pub struct SecretsConfig {
246+ /// Encryption key for secure cookies
247+ #[ schemars( with = "EncryptionRaw" ) ]
248+ #[ serde_as( as = "serde_with::TryFromInto<EncryptionRaw>" ) ]
249+ #[ serde( flatten) ]
250+ encryption : Encryption ,
199251
200252 /// List of private keys to use for signing and encrypting payloads
201253 #[ serde( default ) ]
@@ -216,9 +268,33 @@ impl SecretsConfig {
216268 }
217269
218270 /// Derive an [`Encrypter`] out of the config
219- #[ must_use]
220- pub fn encrypter ( & self ) -> Encrypter {
221- Encrypter :: new ( & self . encryption )
271+ ///
272+ /// # Errors
273+ ///
274+ /// Returns an error when the Encryptor can not be created.
275+ pub async fn encrypter ( & self ) -> anyhow:: Result < Encrypter > {
276+ Ok ( Encrypter :: new ( & self . encryption ( ) . await ?) )
277+ }
278+
279+ /// Returns the encryption secret.
280+ ///
281+ /// # Errors
282+ ///
283+ /// Returns an error when the encryption secret could not be read from file.
284+ pub async fn encryption ( & self ) -> anyhow:: Result < [ u8 ; 32 ] > {
285+ // Read the encryption secret either embedded in the config file or on disk
286+ match self . encryption {
287+ Encryption :: Value ( encryption) => Ok ( encryption) ,
288+ Encryption :: File ( ref path) => {
289+ let mut bytes = [ 0 ; 32 ] ;
290+ let content = tokio:: fs:: read ( path) . await ?;
291+ hex:: decode_to_slice ( content, & mut bytes) . context (
292+ "Content of `encryption_file` must contain hex characters \
293+ encoding exactly 32 bytes",
294+ ) ?;
295+ Ok ( bytes)
296+ }
297+ }
222298 }
223299}
224300
@@ -299,7 +375,7 @@ impl SecretsConfig {
299375 } ;
300376
301377 Ok ( Self {
302- encryption : Standard . sample ( & mut rng) ,
378+ encryption : Encryption :: Value ( Standard . sample ( & mut rng) ) ,
303379 keys : vec ! [ rsa_key, ec_p256_key, ec_p384_key, ec_k256_key] ,
304380 } )
305381 }
@@ -340,7 +416,7 @@ impl SecretsConfig {
340416 } ;
341417
342418 Self {
343- encryption : [ 0xEA ; 32 ] ,
419+ encryption : Encryption :: Value ( [ 0xEA ; 32 ] ) ,
344420 keys : vec ! [ rsa_key, ecdsa_key] ,
345421 }
346422 }
0 commit comments