about summary refs log tree commit diff
diff options
context:
space:
mode:
authorVika Shleina <vika@fireburn.ru>2021-07-21 06:25:15 +0300
committerVika <vika@fireburn.ru>2021-07-27 01:47:59 +0300
commit758fe3ef8baa68e71f766ae5499dfa6988d0d72a (patch)
tree51905753c1abcf8ddde28601ea2d3dbd92607f5e
parentc98e370326102dac0c7c16c9b556da018b41803b (diff)
downloadkittybox-758fe3ef8baa68e71f766ae5499dfa6988d0d72a.tar.zst
Added an internal token mechanism
The internal token is a shared secret that can update and delete any
posts stored in the database. It is intended for use in webmention
endpoints to update posts with latest webmentions.

Please keep it safe.
-rw-r--r--flake.nix13
-rw-r--r--src/indieauth.rs11
-rw-r--r--src/lib.rs4
-rw-r--r--src/main.rs3
4 files changed, 30 insertions, 1 deletions
diff --git a/flake.nix b/flake.nix
index 0ea2d37..d074ab1 100644
--- a/flake.nix
+++ b/flake.nix
@@ -78,6 +78,11 @@
             example = "https://indieauth.com/auth";
             description = "Authorization endpoint to use to authenticate the user. You can use the default if you are unsure.";
           };
+          internalTokenFile = mkOption {
+            type = types.nullOr types.str;
+            example = "/run/secrets/kittybox-shared-secret";
+            description = "A shared secret that will, when passed, allow unlimited editing access to database. Keep it safe.";
+          };
         };
       };
       config = lib.mkIf cfg.enable {
@@ -101,8 +106,14 @@
             REDIS_URI = if (cfg.redisUri == null) then "redis://127.0.0.1:6379/" else cfg.redisUri;
           };
 
+          script = ''
+            if [[ -f ${cfg.internalTokenFile} ]]; then
+              export KITTYBOX_INTERNAL_TOKEN=$(${pkgs.coreutils}/bin/cat ${cfg.internalTokenFile})
+            fi
+            exec ${cfg.package}/bin/kittybox
+          '';
+
           serviceConfig = {
-            ExecStart = "${cfg.package}/bin/kittybox";
             DynamicUser = true;
           };
         };
diff --git a/src/indieauth.rs b/src/indieauth.rs
index 27e545d..aea7e4d 100644
--- a/src/indieauth.rs
+++ b/src/indieauth.rs
@@ -166,6 +166,17 @@ where
                     .build())
             }
             Some(value) => {
+                match (&req.state().internal_token) {
+                    Some(token) => if token == &value.last().to_string().split(" ").skip(1).collect::<String>() {
+                        req.set_ext::<User>(User::new(
+                            "", // no user ID here
+                            "https://kittybox.fireburn.ru/",
+                            "update delete undelete media kittybox_internal:do_what_thou_wilt"
+                        ));
+                        return Ok(next.run(req).await)
+                    }
+                    None => {}
+                }
                 let endpoint = &req.state().token_endpoint;
                 let http_client = &req.state().http_client;
                 let token = value.last().to_string();
diff --git a/src/lib.rs b/src/lib.rs
index d4a63d7..d39aa5e 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -15,6 +15,7 @@ where
     token_endpoint: surf::Url,
     authorization_endpoint: surf::Url,
     media_endpoint: Option<String>,
+    internal_token: Option<String>,
     http_client: surf::Client,
     storage: StorageBackend,
 }
@@ -61,11 +62,13 @@ pub async fn get_app_with_redis(
     authorization_endpoint: surf::Url,
     redis_uri: String,
     media_endpoint: Option<String>,
+    internal_token: Option<String>
 ) -> App<database::RedisStorage> {
     let app = tide::with_state(ApplicationState {
         token_endpoint,
         media_endpoint,
         authorization_endpoint,
+        internal_token,
         storage: database::RedisStorage::new(redis_uri).await.unwrap(),
         http_client: surf::Client::new(),
     });
@@ -92,6 +95,7 @@ pub async fn get_app_with_test_redis(
         media_endpoint: None,
         authorization_endpoint: Url::parse("https://indieauth.com/auth").unwrap(),
         storage: backend.clone(),
+        internal_token: None,
         http_client: surf::Client::new(),
     });
     (redis_instance, backend, equip_app(app))
diff --git a/src/main.rs b/src/main.rs
index 2f7152f..eb7b538 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -58,6 +58,8 @@ async fn main() -> Result<(), std::io::Error> {
 
     let media_endpoint: Option<String> = env::var("MEDIA_ENDPOINT").ok();
 
+    let internal_token: Option<String> = env::var("KITTYBOX_INTERNAL_TOKEN").ok();
+
     let host = env::var("SERVE_AT")
         .ok()
         .unwrap_or_else(|| "0.0.0.0:8080".to_string());
@@ -66,6 +68,7 @@ async fn main() -> Result<(), std::io::Error> {
         authorization_endpoint,
         redis_uri,
         media_endpoint,
+        internal_token
     )
     .await;
     app.listen(host).await