M README.md => README.md +8 -0
@@ 12,6 12,14 @@ A small API for relaying the same message to multiple services.
The following example creates a notifier that sends a message to Gotify and
Matrix.
+### `token` fields
+All `token` fields (service and notifier configs) can also be a path to a
+file containing the token, e.g. `/run/secrets/canwa-matrix-token`
+
+canwa will check if the value is a path that exists and reads it if it is.
+If the value is not a path, or it is a path that cannot be read, it will be
+assumed a raw string token.
+
### Example `canwa.toml`
```toml
interface = "0.0.0.0"
M src/config.rs => src/config.rs +20 -0
@@ 32,8 32,28 @@ pub trait ServiceConfig {
fn as_any(&self) -> &dyn std::any::Any;
}
+pub fn deserialize_token<'de, D>(deserializer: D) -> Result<String, D::Error>
+where
+ D: serde::Deserializer<'de>,
+{
+ let token_or_path: String = serde::de::Deserialize::deserialize(deserializer)?;
+ // If the value exists as a path and we can read it, read the file.
+ let path = std::path::Path::new(&token_or_path);
+ if path.exists() {
+ match std::fs::read_to_string(path) {
+ Ok(token) => return Ok(token.trim().into()),
+ Err(err) => {
+ tracing::warn!(msg="token exists as a filesystem path, but could not be read, assuming raw token", %err)
+ }
+ }
+ }
+ // Assume raw token.
+ Ok(token_or_path)
+}
+
#[derive(Clone, Deserialize)]
pub struct NotifierConfig {
+ #[serde(deserialize_with = "deserialize_token")]
pub token: String,
pub services: Vec<String>,
}
M src/service/gotify.rs => src/service/gotify.rs +2 -1
@@ 8,13 8,14 @@
use async_trait::async_trait;
use serde::{Deserialize, Serialize};
-use crate::config::ServiceConfig;
+use crate::config::{ServiceConfig, deserialize_token};
use super::Service;
#[derive(Clone, Deserialize, Serialize)]
pub struct GotifyConfig {
pub instance: String,
+ #[serde(deserialize_with = "deserialize_token")]
pub token: String,
}
M src/service/matrix.rs => src/service/matrix.rs +2 -1
@@ 9,13 9,14 @@ use async_trait::async_trait;
use serde::{Deserialize, Serialize};
use serde_json::json;
-use crate::config::ServiceConfig;
+use crate::config::{ServiceConfig, deserialize_token};
use super::Service;
#[derive(Clone, Deserialize, Serialize)]
pub struct MatrixConfig {
pub instance: String,
+ #[serde(deserialize_with = "deserialize_token")]
pub token: String,
pub room: String,
}