From 41715bacd5fe6fffd32f6ed1ecc1a6aac2f593cc Mon Sep 17 00:00:00 2001 From: Keagan Date: Tue, 12 May 2026 09:19:42 +0200 Subject: [PATCH 1/7] added endpoint to refresh bundle --- src/source/routes/integrations.clj | 16 ++++++++++++++++ src/source/routes/reitit.clj | 1 + 2 files changed, 17 insertions(+) diff --git a/src/source/routes/integrations.clj b/src/source/routes/integrations.clj index 129e59a..a8333a5 100644 --- a/src/source/routes/integrations.clj +++ b/src/source/routes/integrations.clj @@ -62,3 +62,19 @@ :responses (api/success schemas/IntegrationTypes)} [{:keys [ds]}] (res/response (hon/find ds {:tname :integration-types}))) + +(defn refresh + {:summary "Force rerun of bundle job to refresh integration content" + :parameters (api/params :path [:map [:id {:description "Integration ID"} :int]]) + :responses (-> (api/success [:map [:message :string]]) + (api/unauthorized nil))} + [{:keys [ds js user path-params]}] + (let [{:keys [user-id]} (hon/find-one ds {:tname :bundles + :where [:= :id (:id path-params)]}) + job-id (handlers/update-bundle-job-id (:id path-params))] + (if (or (= user-id (:id user)) (= (:type user) "admin")) + (do + (congest/stop! js job-id false) + (jobs/start! js ds job-id) + (res/response {:message "Successfully restarted bundle job."})) + (res/response {:message "unauthorized"})))) diff --git a/src/source/routes/reitit.clj b/src/source/routes/reitit.clj index cab6fec..aa67b39 100644 --- a/src/source/routes/reitit.clj +++ b/src/source/routes/reitit.clj @@ -178,6 +178,7 @@ ["/:id" (-> (get integration/get) (post integration/post) (delete integration/delete))] + ["/:id/refresh" (get integrations/refresh)] ["/:id/categories" (-> (get integration-categories/get) (post integration-categories/post))] ["/:id/filter/feeds" (get integration-filter-feeds/get)] From 0b1ef0c2a4aed30b54340cbe9a24ff4d40801fe8 Mon Sep 17 00:00:00 2001 From: Keagan Date: Tue, 12 May 2026 10:07:35 +0200 Subject: [PATCH 2/7] updated endpoint to manually call handler instead --- src/source/jobs/handlers.clj | 2 +- src/source/routes/integrations.clj | 21 ++++++++++++++------- 2 files changed, 15 insertions(+), 8 deletions(-) diff --git a/src/source/jobs/handlers.clj b/src/source/jobs/handlers.clj index 91bf85a..39aa007 100644 --- a/src/source/jobs/handlers.clj +++ b/src/source/jobs/handlers.clj @@ -20,7 +20,7 @@ (defmethod handler :test [_] (fn [{:keys [args]}] - (println "hello" (get args :name) args))) + (println "hello" (:name args) args))) (defn update-feed-posts-job-id "returns the job id of an update-feed-posts job with the given email and feed-id" diff --git a/src/source/routes/integrations.clj b/src/source/routes/integrations.clj index a8333a5..6b64069 100644 --- a/src/source/routes/integrations.clj +++ b/src/source/routes/integrations.clj @@ -9,7 +9,8 @@ [source.routes.openapi :as api] [source.workers.schemas :as schemas] [source.db.honey :as hon] - [malli.util :as mu])) + [malli.util :as mu] + [source.db.util :as db.util])) (defn get {:summary "Get metadata of all integrations on the user account" @@ -68,13 +69,19 @@ :parameters (api/params :path [:map [:id {:description "Integration ID"} :int]]) :responses (-> (api/success [:map [:message :string]]) (api/unauthorized nil))} - [{:keys [ds js user path-params]}] - (let [{:keys [user-id]} (hon/find-one ds {:tname :bundles - :where [:= :id (:id path-params)]}) - job-id (handlers/update-bundle-job-id (:id path-params))] + [{:keys [ds user path-params]}] + (let [bundle-id (:id path-params) + {:keys [user-id]} (hon/find-one ds {:tname :bundles + :where [:= :id bundle-id]}) + categories (->> (-> {:where [:= :bundle-id bundle-id]} + (db.util/tname :bundle-categories bundle-id)) + (hon/find ds) + (mapv #(assoc {} :id (:category-id %))))] (if (or (= user-id (:id user)) (= (:type user) "admin")) (do - (congest/stop! js job-id false) - (jobs/start! js ds job-id) + ((handlers/handler {:handler :update-bundle}) + {:ds ds + :args {:bundle-id bundle-id + :categories categories}}) (res/response {:message "Successfully restarted bundle job."})) (res/response {:message "unauthorized"})))) From 3000e48ff278276c675e33292266bced9a604000 Mon Sep 17 00:00:00 2001 From: Keagan <51060273+toasted226@users.noreply.github.com> Date: Tue, 12 May 2026 10:09:17 +0200 Subject: [PATCH 3/7] update argument access in test handler --- src/source/jobs/handlers.clj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/source/jobs/handlers.clj b/src/source/jobs/handlers.clj index 39aa007..91bf85a 100644 --- a/src/source/jobs/handlers.clj +++ b/src/source/jobs/handlers.clj @@ -20,7 +20,7 @@ (defmethod handler :test [_] (fn [{:keys [args]}] - (println "hello" (:name args) args))) + (println "hello" (get args :name) args))) (defn update-feed-posts-job-id "returns the job id of an update-feed-posts job with the given email and feed-id" From 5a5c57d9f754b9eae82b78b6997055b8e63c5f6b Mon Sep 17 00:00:00 2001 From: Keagan Date: Tue, 12 May 2026 13:26:57 +0200 Subject: [PATCH 4/7] replaced authz logic in endpoint with middleware --- src/source/middleware/auth/core.clj | 24 +++++++++++++++++++++++- src/source/routes/integrations.clj | 17 ++++++----------- src/source/routes/reitit.clj | 6 ++++-- src/source/routes/util.clj | 12 ++++++++++++ 4 files changed, 45 insertions(+), 14 deletions(-) diff --git a/src/source/middleware/auth/core.clj b/src/source/middleware/auth/core.clj index bb5032d..320d065 100644 --- a/src/source/middleware/auth/core.clj +++ b/src/source/middleware/auth/core.clj @@ -4,7 +4,9 @@ [ring.util.response :as res] [source.services.bundles :as bundles] [source.db.honey :as db] - [taoensso.telemere :as t])) + [taoensso.telemere :as t] + [source.db.honey :as hon] + [pg.core :as pg])) (defn create-session [user] (let [payload {:id (:id user) @@ -53,6 +55,26 @@ (res/response {:message "Unauthorized"}) (res/status 401)))))) +(defn wrap-integration-auth + "returns an unauthorized response if the integration id is not owned by this user and the user is not an admin" + [handler] + (fn [{:keys [ds user path-params] :as request}] + (cond + (= (:type user) "admin") + (handler request) + + (and (= (:type user) "distributor") + (pg/execute + ds + "SELECT EXISTS(SELECT 1 FROM bundles WHERE id = $1 AND user_id = $2) AS exists" + {:params [(:id path-params) + (:id user)]})) + (handler request) + + :else + (-> (res/response {:message "unauthorized"}) + (res/status 401))))) + (defn wrap-bundle-id "validates the bundle uuid in the query parameters of the request for unauthenticated users and attaches the bundle-id to the request" diff --git a/src/source/routes/integrations.clj b/src/source/routes/integrations.clj index 6b64069..df3a2cc 100644 --- a/src/source/routes/integrations.clj +++ b/src/source/routes/integrations.clj @@ -69,19 +69,14 @@ :parameters (api/params :path [:map [:id {:description "Integration ID"} :int]]) :responses (-> (api/success [:map [:message :string]]) (api/unauthorized nil))} - [{:keys [ds user path-params]}] + [{:keys [ds path-params]}] (let [bundle-id (:id path-params) - {:keys [user-id]} (hon/find-one ds {:tname :bundles - :where [:= :id bundle-id]}) categories (->> (-> {:where [:= :bundle-id bundle-id]} (db.util/tname :bundle-categories bundle-id)) (hon/find ds) (mapv #(assoc {} :id (:category-id %))))] - (if (or (= user-id (:id user)) (= (:type user) "admin")) - (do - ((handlers/handler {:handler :update-bundle}) - {:ds ds - :args {:bundle-id bundle-id - :categories categories}}) - (res/response {:message "Successfully restarted bundle job."})) - (res/response {:message "unauthorized"})))) + ((handlers/handler {:handler :update-bundle}) + {:ds ds + :args {:bundle-id bundle-id + :categories categories}}) + (res/response {:message "Successfully restarted bundle job."}))) diff --git a/src/source/routes/reitit.clj b/src/source/routes/reitit.clj index aa67b39..43dda91 100644 --- a/src/source/routes/reitit.clj +++ b/src/source/routes/reitit.clj @@ -74,7 +74,8 @@ [source.routes.job-stop :as job-stop] [source.routes.report :as report] [source.routes.approve-feed :as approve-feed] - [source.routes.reject-feed :as reject-feed])) + [source.routes.reject-feed :as reject-feed] + [source.middleware.auth.core :as auth])) (defn create-app [{:keys [ds js]}] (ring/ring-handler @@ -178,7 +179,8 @@ ["/:id" (-> (get integration/get) (post integration/post) (delete integration/delete))] - ["/:id/refresh" (get integrations/refresh)] + ["/:id/refresh" (-> (get integrations/refresh) + (rutil/mw auth/wrap-integration-auth))] ["/:id/categories" (-> (get integration-categories/get) (post integration-categories/post))] ["/:id/filter/feeds" (get integration-filter-feeds/get)] diff --git a/src/source/routes/util.clj b/src/source/routes/util.clj index 03569cb..07c2d06 100644 --- a/src/source/routes/util.clj +++ b/src/source/routes/util.clj @@ -117,3 +117,15 @@ :default-values true :options nil}) :middleware middleware}}) + +(defn middleware [& middlewares] + (let [[route-map mws] (apply parse-route-opts middlewares) + middleware (:middleware route-map) + mws (-> (or middleware []) + (concat mws))] + (->> mws + (mapv #(if (vector? %) % [%])) + (assoc route-map :middleware)))) + +(defn mw [& middlewares] + (apply middleware middlewares)) From 0978c5bcd0fc4eedf17dd4e984ce2b684449d0ae Mon Sep 17 00:00:00 2001 From: Keagan Date: Tue, 12 May 2026 13:50:48 +0200 Subject: [PATCH 5/7] fixed integer parsing --- src/source/middleware/auth/core.clj | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/source/middleware/auth/core.clj b/src/source/middleware/auth/core.clj index 320d065..ae9de96 100644 --- a/src/source/middleware/auth/core.clj +++ b/src/source/middleware/auth/core.clj @@ -64,11 +64,15 @@ (handler request) (and (= (:type user) "distributor") - (pg/execute - ds - "SELECT EXISTS(SELECT 1 FROM bundles WHERE id = $1 AND user_id = $2) AS exists" - {:params [(:id path-params) - (:id user)]})) + (-> + (pg/execute + ds + "SELECT EXISTS(SELECT 1 FROM bundles WHERE id = $1 AND user_id = $2) AS exists" + {:params [(Integer/parseInt (:id path-params)) + (:id user)]}) + (first) + (:exists))) + (handler request) :else From 26bce29ba90c67c4b116560fd29f5a6ed0be77cb Mon Sep 17 00:00:00 2001 From: Keagan Date: Thu, 14 May 2026 07:54:12 +0200 Subject: [PATCH 6/7] moved sql function to worker --- src/source/middleware/auth/core.clj | 18 +++++++----------- src/source/workers/bundles.clj | 13 ++++++++++++- 2 files changed, 19 insertions(+), 12 deletions(-) diff --git a/src/source/middleware/auth/core.clj b/src/source/middleware/auth/core.clj index ae9de96..0aeefd3 100644 --- a/src/source/middleware/auth/core.clj +++ b/src/source/middleware/auth/core.clj @@ -5,8 +5,7 @@ [source.services.bundles :as bundles] [source.db.honey :as db] [taoensso.telemere :as t] - [source.db.honey :as hon] - [pg.core :as pg])) + [source.workers.bundles :as bundles-worker])) (defn create-session [user] (let [payload {:id (:id user) @@ -64,15 +63,12 @@ (handler request) (and (= (:type user) "distributor") - (-> - (pg/execute - ds - "SELECT EXISTS(SELECT 1 FROM bundles WHERE id = $1 AND user_id = $2) AS exists" - {:params [(Integer/parseInt (:id path-params)) - (:id user)]}) - (first) - (:exists))) - + (bundles-worker/user-owns-bundle? + ds + (:id user) + (try + (Integer/parseInt (:id path-params)) + (catch Exception _ nil)))) (handler request) :else diff --git a/src/source/workers/bundles.clj b/src/source/workers/bundles.clj index 9ec696c..1b6caf3 100644 --- a/src/source/workers/bundles.clj +++ b/src/source/workers/bundles.clj @@ -2,7 +2,8 @@ (:require [source.db.honey :as hon] [honey.sql.helpers :as hsql] [source.db.util :as db.util] - [source.prandom.core :as prandom]) + [source.prandom.core :as prandom] + [pg.core :as pg]) (:import [java.time LocalDateTime] [java.time.format DateTimeFormatter])) @@ -111,6 +112,16 @@ :next-index (when (and next-index (< next-index total-size)) next-index)} :data limited-posts})) +(defn user-owns-bundle? [ds user-id bundle-id] + (-> + (pg/execute + ds + "SELECT EXISTS(SELECT 1 FROM bundles WHERE id = $1 AND user_id = $2) AS exists" + {:params [bundle-id + user-id]}) + (first) + (:exists))) + (comment (time (get-outgoing-posts (db.util/conn) {:bundle-id 14 From 73e31951ff4786e1bd95408fae4a17d663b4664f Mon Sep 17 00:00:00 2001 From: Keagan Date: Thu, 14 May 2026 08:01:23 +0200 Subject: [PATCH 7/7] validated path param --- src/source/middleware/auth/core.clj | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/src/source/middleware/auth/core.clj b/src/source/middleware/auth/core.clj index 0aeefd3..2b7486c 100644 --- a/src/source/middleware/auth/core.clj +++ b/src/source/middleware/auth/core.clj @@ -58,22 +58,22 @@ "returns an unauthorized response if the integration id is not owned by this user and the user is not an admin" [handler] (fn [{:keys [ds user path-params] :as request}] - (cond - (= (:type user) "admin") - (handler request) + (let [bundle-id (try (Integer/parseInt (:id path-params)) (catch Exception _ nil))] + (cond + (nil? bundle-id) + (-> (res/response {:message "unauthorized"}) + (res/status 403)) + + (= (:type user) "admin") + (handler request) - (and (= (:type user) "distributor") - (bundles-worker/user-owns-bundle? - ds - (:id user) - (try - (Integer/parseInt (:id path-params)) - (catch Exception _ nil)))) - (handler request) + (and (= (:type user) "distributor") + (bundles-worker/user-owns-bundle? ds bundle-id (:id user))) + (handler request) - :else - (-> (res/response {:message "unauthorized"}) - (res/status 401))))) + :else + (-> (res/response {:message "unauthorized"}) + (res/status 403)))))) (defn wrap-bundle-id "validates the bundle uuid in the query parameters of the request for