Merge branch 'fixes' into 'master'

convert info logs to debug to remove logging bloat

See merge request ZeusWPI/cat!2
This commit is contained in:
flynn 2019-06-09 01:02:46 +02:00
commit 10e78737e2
11 changed files with 292 additions and 268 deletions

View file

@ -4,14 +4,16 @@
;:url "http://example.com/FIXME" ;:url "http://example.com/FIXME"
:dependencies [[buddy "2.0.0"] :dependencies [[buddy "2.0.0"]
[com.cemerick/friend "0.2.3"]
[cheshire "5.8.1"] [cheshire "5.8.1"]
[clj-oauth "1.5.5"] [clj-oauth "1.5.5"]
[clojure.java-time "0.3.2"] [clojure.java-time "0.3.2"]
[com.cemerick/friend "0.2.3"]
[com.cognitect/transit-clj "0.8.313"] [com.cognitect/transit-clj "0.8.313"]
[com.google.protobuf/protobuf-java "3.6.1"]
[compojure "1.6.1"] [compojure "1.6.1"]
[conman "0.8.3"] [conman "0.8.3"]
[cprop "0.1.13"] [cprop "0.1.13"]
[funcool/promesa "1.9.0"]
[funcool/struct "1.3.0"] [funcool/struct "1.3.0"]
[luminus-immutant "0.2.4"] [luminus-immutant "0.2.4"]
[luminus-migrations "0.6.3"] [luminus-migrations "0.6.3"]
@ -20,16 +22,15 @@
[markdown-clj "1.0.5"] [markdown-clj "1.0.5"]
[metosin/muuntaja "0.6.3"] [metosin/muuntaja "0.6.3"]
[metosin/ring-http-response "0.9.1"] [metosin/ring-http-response "0.9.1"]
[slingshot "0.12.1"] [metosin/vega-tools "0.2.0"]
[mount "0.1.15"] [mount "0.1.15"]
[mysql/mysql-connector-java "8.0.12"]
[nrepl "0.5.3"] [nrepl "0.5.3"]
[org.clojure/clojure "1.10.0"] [org.clojure/clojure "1.10.0"]
[org.clojure/clojurescript "1.10.439" :scope "provided"] [org.clojure/clojurescript "1.10.439" :scope "provided"]
[org.clojure/tools.cli "0.4.1"] [org.clojure/tools.cli "0.4.1"]
[org.clojure/tools.logging "0.4.1"] [org.clojure/tools.logging "0.4.1"]
;[org.postgresql/postgresql "42.2.5"] ;[org.postgresql/postgresql "42.2.5"]
[mysql/mysql-connector-java "8.0.12"]
[com.google.protobuf/protobuf-java "3.6.1"]
;https://www.webjars.org/ ;https://www.webjars.org/
[org.webjars.npm/bulma "0.7.2"] [org.webjars.npm/bulma "0.7.2"]
[org.webjars/font-awesome "5.6.1"] [org.webjars/font-awesome "5.6.1"]
@ -38,8 +39,7 @@
[ring/ring-core "1.7.1"] [ring/ring-core "1.7.1"]
[ring/ring-defaults "0.3.2"] [ring/ring-defaults "0.3.2"]
[selmer "1.12.5"] [selmer "1.12.5"]
[metosin/vega-tools "0.2.0"] [slingshot "0.12.1"]]
[funcool/promesa "1.9.0"]]
@ -81,8 +81,6 @@
:infer-externs true :infer-externs true
:closure-warnings :closure-warnings
{:externs-validation :off :non-standard-jsdoc :off}}}}} {:externs-validation :off :non-standard-jsdoc :off}}}}}
:aot :all :aot :all
:uberjar-name "cat.jar" :uberjar-name "cat.jar"
:source-paths ["env/prod/clj"] :source-paths ["env/prod/clj"]

View file

@ -47,7 +47,6 @@
{% if message %} {% if message %}
<h4 class="subtitle is-5 has-text-danger">{{message}}</h4> <h4 class="subtitle is-5 has-text-danger">{{message}}</h4>
{% endif %} {% endif %}
</div> </div>
</div> </div>
</div> </div>

View file

@ -71,7 +71,7 @@
<a class="button is-light" href="/admin/enable"> <a class="button is-light" href="/admin/enable">
<strong>Enable admin</strong> <strong>Enable admin</strong>
</a> </a>
{%endif%} {% endif %}
{% endif %} {% endif %}
{% if user %} {% if user %}

View file

@ -32,10 +32,9 @@
(when repl-server (when repl-server
(nrepl/stop repl-server))) (nrepl/stop repl-server)))
(defn stop-app [] (defn stop-app []
(doseq [component (:stopped (mount/stop))] (doseq [component (:stopped (mount/stop))]
(log/info component "stopped")) (log/debug component "stopped"))
(shutdown-agents)) (shutdown-agents))
(defn start-app [args] (defn start-app [args]
@ -63,4 +62,3 @@
(System/exit 0)) (System/exit 0))
:else :else
(start-app args))) (start-app args)))

View file

@ -1,30 +1,53 @@
(ns cat.handler (ns cat.handler
(:require [cat.middleware :as middleware] (:require [cat.middleware :as middleware]
[cat.layout :refer [error-page]] [cat.layout :refer [error-page]]
[cat.routes.home :refer [home-routes]] [cat.routes.home :refer [show-home show-relations update-relationrequest-status create-relation-request]]
[cat.routes.oauth :refer [oauth-routes admin-routes]] [cat.routes.oauth :refer [oauth-init oauth-callback clear-session!]]
[compojure.core :refer [routes wrap-routes]] [cat.routes.admin :refer [set-admin! create-new-relation! create-user!]]
[compojure.core :refer [routes defroutes GET POST wrap-routes]]
[ring.util.http-response :as response] [ring.util.http-response :as response]
[compojure.route :as route] [compojure.route :as route]
[cat.env :refer [defaults]] [cat.env :refer [defaults]]
[clojure.tools.logging :as log]
[mount.core :as mount])) [mount.core :as mount]))
(mount/defstate init-app (mount/defstate init-app
:start ((or (:init defaults) identity)) :start ((or (:init defaults) identity))
:stop ((or (:stop defaults) identity))) :stop ((or (:stop defaults) identity)))
(mount/defstate app (defroutes public-routes
:start (GET "/" req (show-home req))
(middleware/wrap-base (GET "/relations_zeroed" [] (show-relations)))
(routes
(-> #'home-routes (defroutes user-routes
(wrap-routes middleware/wrap-csrf) (POST "/relation_request/:id/status" [id & body] (update-relationrequest-status id body)) ; STATUS ENUM: (open, accepted, rejected)
(wrap-routes middleware/wrap-formats)) (POST "/request_relation" req (create-relation-request req)))
#'oauth-routes
(-> #'admin-routes (defroutes oauth-routes
(wrap-routes middleware/wrap-restricted)) (GET "/oauth/oauth-init" req (oauth-init req))
(GET "/oauth/oauth-callback" req (oauth-callback req))
(GET "/logout" req (clear-session! "/")))
(defroutes admin-routes
(GET "/admin/enable" req (set-admin! req true))
(GET "/admin/disable" req (set-admin! req false))
(POST "/relations" req (create-new-relation! req))
(POST "/users" req (create-user! req)))
(defroutes app-routes
(-> public-routes
middleware/wrap-csrf
middleware/wrap-formats)
user-routes
oauth-routes
admin-routes
(route/not-found (route/not-found
(:body (:body
(error-page {:status 404 (error-page {:status 404
:title "page not found"})))))) :title "page not found"}))))
(mount/defstate app
:start
(-> app-routes
middleware/wrap-base))

View file

@ -18,7 +18,6 @@
[buddy.auth.backends.session :refer [session-backend]]) [buddy.auth.backends.session :refer [session-backend]])
(:import)) (:import))
(defn wrap-internal-error [handler] (defn wrap-internal-error [handler]
(fn [req] (fn [req]
(try (try
@ -37,7 +36,6 @@
{:status 403 {:status 403
:title "Invalid anti-forgery token"})})) :title "Invalid anti-forgery token"})}))
(defn wrap-formats [handler] (defn wrap-formats [handler]
(let [wrapped (-> handler wrap-params (wrap-format formats/instance))] (let [wrapped (-> handler wrap-params (wrap-format formats/instance))]
(fn [request] (fn [request]
@ -45,24 +43,49 @@
;; since they're not compatible with this middleware ;; since they're not compatible with this middleware
((if (:websocket? request) handler wrapped) request)))) ((if (:websocket? request) handler wrapped) request))))
(defn on-error [request response] ;; Authentication
(defn admin-access [req]
(contains? (get-in req [:session :user :roles]) :admin))
(def rules
"The authentication rules"
[{:pattern #"^/admin/.*"
:handler admin-access}
; TODO add other auth schemes
;{:pattern [#"^/$" #"^/oauth/.*"]
; :handler any-access}
;{:pattern #"^/.*"
; :handler user-access}
])
(defn on-auth-error
[request response]
(error-page (error-page
{:status 403 {:status 403
:title (str "Access to " (:uri request) " is not authorized")})) :title (str "Access to " (:uri request) " is not authorised")}))
(defn wrap-restricted [handler] (defn wrap-restricted
"Example of how to wrap a route or handling in an authentication scheme"
[handler]
(restrict handler {:handler authenticated? (restrict handler {:handler authenticated?
:on-error on-error})) :on-error on-auth-error}))
(defn wrap-auth [handler] (defn wrap-auth
"Installs the session backend on ring"
[handler]
(let [backend (session-backend)] (let [backend (session-backend)]
(-> handler (-> handler
(wrap-authentication backend) (wrap-authentication backend)
(wrap-authorization backend)))) (wrap-authorization backend))))
(defn wrap-base [handler] (defn wrap-base
"The all default middleware functions. These get applied to every route."
[handler]
(-> ((:middleware defaults) handler) (-> ((:middleware defaults) handler)
wrap-auth wrap-auth
(wrap-access-rules {:rules rules
:on-error on-auth-error})
wrap-webjars wrap-webjars
wrap-flash wrap-flash
(wrap-session {:cookie-attrs {:http-only true}}) (wrap-session {:cookie-attrs {:http-only true}})

View file

@ -12,14 +12,13 @@
:client-secret (env :oauth-consumer-secret) :client-secret (env :oauth-consumer-secret)
:authorize-uri (env :authorize-uri) :authorize-uri (env :authorize-uri)
:redirect-uri (str (env :app-host) "/oauth/oauth-callback") :redirect-uri (str (env :app-host) "/oauth/oauth-callback")
:access-token-uri (env :access-token-uri) :access-token-uri (env :access-token-uri)})
})
; To authorize, redirect the user to the sign in / grant page ; To authorize, redirect the user to the sign in / grant page
(defn- authorize-uri (defn- authorize-uri
[client-params ;csrf-token [client-params #_csrf-token]
]
(str (str
(:authorize-uri client-params) (:authorize-uri client-params)
"?" "?"
@ -41,7 +40,7 @@
"let the user authorize access by redirecting to the signin / grant page "let the user authorize access by redirecting to the signin / grant page
of the used oauth api" of the used oauth api"
[] []
(log/info "Oauth params: " (oauth2-params)) ; (log/info "Oauth params: " (oauth2-params))
(authorize-uri (oauth2-params))) (authorize-uri (oauth2-params)))
(defn get-authentication-response (defn get-authentication-response
@ -50,22 +49,23 @@
(if (or true (= csrf-token state)) (if (or true (= csrf-token state))
(try (try
(do (do
(log/info "Requesting access token with code " code) (log/debug "Requesting access token with code " code)
(let [oauth2-params (oauth2-params) (let [oauth2-params (oauth2-params)
access-token (httpclient/post (:access-token-uri oauth2-params) resp (httpclient/post (:access-token-uri oauth2-params)
{:form-params {:code code {:form-params {:code code
:grant_type "authorization_code" :grant_type "authorization_code"
:client_id (:client-id oauth2-params) :client_id (:client-id oauth2-params)
:client_secret (:client-secret oauth2-params) :client_secret (:client-secret oauth2-params)
:redirect_uri (:redirect-uri oauth2-params)} :redirect_uri (:redirect-uri oauth2-params)}
;:basic-auth [(:client-id oauth2-params) (:client-secret oauth2-params)]
:as :json :as :json
:insecure? true :throw-exceptions false
})] :insecure? true})]
(println "Access token response:" access-token) (condp = (:status resp)
(:body access-token))) 200 (:body resp)
(catch Exception e (log/error "Something terrible happened..." e))) 401 (-> {:status 401 :body "Invalid authentication credentials"})
nil)) {:status 500 :body "Something went pear-shape when trying to authenticate"})))
)
(log/info "Invalid csrf token whilst authenticating")))
(defn get-user-info (defn get-user-info
"User info API call" "User info API call"
@ -74,10 +74,11 @@
(-> (httpclient/get url {:oauth-token access-token (-> (httpclient/get url {:oauth-token access-token
:as :json :as :json
:insecure? true}) :insecure? true})
:body) :body)))
))
; Refresh token when it expires ; Refresh token when it expires
(defn- refresh-tokens (defn- refresh-tokens
"Request a new token pair" "Request a new token pair"
[refresh-token] [refresh-token]

View file

@ -0,0 +1,39 @@
(ns cat.routes.admin
(:require [cat.db.core :refer [*db*] :as db]
[struct.core :as st]
[clojure.tools.logging :as log]
[ring.util.http-response :as response]))
(def user-schema
[[:name st/required st/string]
[:gender st/string]])
(def relation-schema
[[:from_id st/required st/integer-str]
[:to_id st/required st/integer-str]])
(defn set-admin! [req enabled?]
(-> (response/found "/")
(assoc :session (assoc-in (:session req) [:user :admin :enabled] enabled?))))
(defn create-new-relation! [req]
(let [data (:params req)
[err result] (st/validate data relation-schema)]
(if (nil? err)
(do
(log/info "Admin creates relation from " (:from_id data) "to" (:to_id data))
(db/create-relation! result)
(response/found "/"))
(do
(response/bad-request "Incorrect input")))))
(defn create-user! [req]
(let [data (:params req)]
(println data)
(if (st/valid? data user-schema)
(do
(log/info "Admin creates user: " (:name data))
(db/create-user! (assoc data :zeusid nil))
(response/found "/"))
(do
(response/bad-request "Incorrect input")))))

View file

@ -9,35 +9,26 @@
[cat.layout :refer [error-page]] [cat.layout :refer [error-page]]
[clojure.string :as s])) [clojure.string :as s]))
(def user-schema
[[:name st/required st/string]
[:gender st/string]])
(def relation-schema
[[:from_id st/required st/integer-str]
[:to_id st/required st/integer-str]])
(def request_relation-schema (def request_relation-schema
[[:to_id st/required st/integer-str]]) [[:to_id st/required st/integer-str]])
(defn home-page [params] (defn- home-page [params]
(layout/render "home.html" params)) (layout/render "home.html" params))
(defn get-relations [] (defn- get-relations []
(map (map
(fn [relation] (select-keys relation [:name :name_2])) (fn [relation] (select-keys relation [:name :name_2]))
(db/get-relations))) (db/get-relations)))
(defn get-users [] (defn- get-users []
(db/get-users)) (db/get-users))
(defn response-wrong-parameters [] (defn- response-wrong-parameters []
(error-page {:status 400 (error-page {:status 400
:title "Wrong request parameters" :title "Wrong request parameters"
:message "Please contact your system administrator to fix this issue"})) :message "Please contact your system administrator to fix this issue"}))
(defroutes home-routes (defn show-home [req]
(GET "/" req
(let [users (get-users) (let [users (get-users)
relations (get-relations) relations (get-relations)
user (-> (get-in req [:session :user])) user (-> (get-in req [:session :user]))
@ -53,7 +44,7 @@
rel-requests-out (seq (db/get-relation-requests-from-user {:from_id (:id user)})) rel-requests-out (seq (db/get-relation-requests-from-user {:from_id (:id user)}))
rel-requests-in (seq (db/get-relation-requests-to-user {:to_id (:id user)})) rel-requests-in (seq (db/get-relation-requests-to-user {:to_id (:id user)}))
non_requested_users (seq (filter (fn [other-user] (not (some (partial = (:id other-user)) (map :to_id rel-requests-out)))) other_users))] non_requested_users (seq (filter (fn [other-user] (not (some (partial = (:id other-user)) (map :to_id rel-requests-out)))) other_users))]
(log/info (str "Session: " (:session req))) (log/debug (str "Session: " (:session req)))
;(log/info (str "Relation requests: \n OUTGOING: " rel-requests-out "\n INCOMING: " rel-requests-in)) ;(log/info (str "Relation requests: \n OUTGOING: " rel-requests-out "\n INCOMING: " rel-requests-in))
;(log/info (str "User relations: " user-relations)) ;(log/info (str "User relations: " user-relations))
;(log/info (str "Other Users: " other_users)) ;(log/info (str "Other Users: " other_users))
@ -67,13 +58,9 @@
:rel-requests-in rel-requests-in :rel-requests-in rel-requests-in
:non_requested_users non_requested_users :non_requested_users non_requested_users
:flash (:flash req)}))) :flash (:flash req)})))
;(GET "/docs" []
; (-> (response/ok (-> "docs/docs.md" io/resource slurp)) (defn show-relations
; (response/header "Content-Type" "text/plain; charset=utf-8"))) []
(GET "/relations" []
(let []
(response/ok {})))
(GET "/relations_zeroed" []
(let [users (db/get-users) (let [users (db/get-users)
relations (db/get-relations) relations (db/get-relations)
used-node-ids (set (flatten (map (fn [ln] [(:from_id ln) (:to_id ln)]) relations))) used-node-ids (set (flatten (map (fn [ln] [(:from_id ln) (:to_id ln)]) relations)))
@ -97,28 +84,31 @@
(response/ok {:nodes nodes-indexed (response/ok {:nodes nodes-indexed
:links rels-indexed}))) :links rels-indexed})))
; TODO make next 2 user protected (defn update-relationrequest-status
(POST "/relation_request/:id/status" [id & body] [id body]
(let [rr_id_map {:id id} (let [rr_id_map {:id id}
success (cond success (cond
(contains? body :accept) (do (contains? body :accept)
(do
(let [rr (db/get-relation-request rr_id_map)] (let [rr (db/get-relation-request rr_id_map)]
(db/create-relation! {:from_id (:from_id rr) :to_id (:to_id rr)})) (db/create-relation! {:from_id (:from_id rr) :to_id (:to_id rr)}))
(db/update-relation-request-status! (assoc rr_id_map :status "accepted"))) (db/update-relation-request-status! (assoc rr_id_map :status "accepted")))
(contains? body :decline) (db/update-relation-request-status! (assoc rr_id_map :status "declined")) (contains? body :decline)
(db/update-relation-request-status! (assoc rr_id_map :status "declined"))
:else false)] :else false)]
(if success (if success
(response/found "/") (response/found "/")
(response-wrong-parameters)))) (response-wrong-parameters))))
; STATUS ENUM: (open, accepted, rejected)
(POST "/request_relation" req (defn create-relation-request
[req]
(let [data (:params req) (let [data (:params req)
[err result] (st/validate data request_relation-schema) [err result] (st/validate data request_relation-schema)
from-id (get-in req [:session :user :id])] from-id (get-in req [:session :user :id])]
(if (nil? from-id) (response/found (error-page (if (nil? from-id) (response/found (error-page
{:status 400 {:status 400
:title "No user id found in session"}))) :title "No user id found in session"})))
(log/info "Post to " (:uri req) "\n with data " result) (log/debug "Post to " (:uri req) "\n with data " result)
(if (nil? err) (if (nil? err)
(do (do
(log/debug "Create relation request") (log/debug "Create relation request")
@ -130,29 +120,3 @@
(log/debug "Relation request failed") (log/debug "Relation request failed")
(log/debug err) (log/debug err)
(response/unprocessable-entity "Incorrect input"))))) (response/unprocessable-entity "Incorrect input")))))
; TODO make bottom 2 admin protected
(POST "/relations" req
(let [data (:params req) [err result] (st/validate data relation-schema)]
(log/info "Post to " (:uri req))
(if (nil? err)
(do
(db/create-relation! result)
(response/found "/"))
(do
(response/bad-request "Incorrect input")))))
(POST "/users" req
(let [data (:params req)]
(log/info "Post to " (:uri req))
(println data)
(if (st/valid? data user-schema)
(do
(db/create-user! (assoc data :zeusid nil))
(response/found "/"))
(do
(response/bad-request "Incorrect input"))))))

View file

@ -10,12 +10,13 @@
(def admins [{:name "flynn" :zeusid 117}]) (def admins [{:name "flynn" :zeusid 117}])
(defn set-user! [user session redirect-url] (defn set-user! [user session redirect-url]
(log/info "Set user in session: " user) (log/debug "Set user in session: " user)
(let [new-session (-> session (let [new-session (-> session
(assoc :user user) (assoc :user user)
(cond-> (some (partial = (select-keys user [:zeusid :name])) admins) (cond-> (some (partial = (select-keys user [:zeusid :name])) admins)
(-> (->
(assoc-in [:user :admin] {:enabled false}) (assoc-in [:user :admin] {:enabled false})
(assoc-in [:user :roles] #{:admin})
(assoc :identity "foo"))))] (assoc :identity "foo"))))]
(-> (found redirect-url) (-> (found redirect-url)
(assoc :session new-session)))) (assoc :session new-session))))
@ -29,10 +30,10 @@
(assoc :session nil))) (assoc :session nil)))
(defn oauth-init (defn oauth-init
"Initiates the Twitter OAuth" "Initiates the OAuth"
[request] [request]
(let [reee (mo/authorize-api-uri)] (let [reee (mo/authorize-api-uri)]
(log/info "authorize uri: " reee) (log/debug "authorize uri: " reee)
(-> reee (-> reee
found))) found)))
@ -40,19 +41,16 @@
"Handles the callback from adams with the access_token "Handles the callback from adams with the access_token
Fetches the user from the database, creating a new one if not found Fetches the user from the database, creating a new one if not found
Sets the user in the session and redirects back to origin \"/\" " Sets the user in the session and redirects back to origin \"/\" "
[req_token {:keys [params session]}]
[{:keys [params session]}]
; oauth request was denied by user ; oauth request was denied by user
(if (:denied params) (if (:denied params)
(-> (found "/") (-> (found "/")
(assoc :flash {:denied true})) (assoc :flash {:denied true}))
; fetch the request token and do anything else you wanna do if not denied. ; fetch the request token and do anything else you wanna do if not denied.
(let [{:keys [access_token refresh_token]} (mo/get-authentication-response nil req_token)] (let [{:keys [access_token refresh_token]} (mo/get-authentication-response nil params)
(log/info "Successfully fetched access-id: " access_token) fetched-user (mo/get-user-info access_token)
(log/info "Fetching user info") local-user (db/get-zeus-user {:zeusid (:id fetched-user)})]
(let [fetched-user (mo/get-user-info access_token)]
(log/info "Fetched user info: " fetched-user)
(let [local-user (db/get-zeus-user {:zeusid (:id fetched-user)})]
(log/info "Zeus user from db: " local-user)
(if local-user (if local-user
(set-user! local-user session "/") (set-user! local-user session "/")
(try (try
@ -60,30 +58,11 @@
:gender nil :gender nil
:zeusid (:id fetched-user)} :zeusid (:id fetched-user)}
generated-key (-> user-template generated-key (-> user-template
(db/create-user!,,,))] (db/create-user!))]
(log/info "Created user: " generated-key)
(set-user! (assoc user-template :id (:generated_key generated-key)) session "/")) (set-user! (assoc user-template :id (:generated_key generated-key)) session "/"))
(catch Exception e (catch Exception e
(do (do
(log/warn "fetched user" fetched-user "already exists, but was not found") (log/warn "fetched user" fetched-user "already exists, but was not found")
(log/warn (:cause (Throwable->map e))) (log/warn (:cause (Throwable->map e)))
(-> (found "/") (-> (found "/")
(assoc :flash {:error "An error occurred, please try again."}))) (assoc :flash {:error "An error occurred, please try again."})))))))))
))))))))
;(catch [:status 401] _
; (error-page {:status 401
; :title "Error authenticating"
; :message "Please contact your system administrator to fix this issue"}))
(defroutes oauth-routes
(GET "/oauth/oauth-init" req (oauth-init req))
(GET "/oauth/oauth-callback" [& req_token :as req] (oauth-callback req_token req))
(GET "/logout" req (clear-session! "/")))
(defroutes admin-routes
(GET "/admin/enable" req (-> (found "/")
(assoc :session (assoc-in (:session req) [:user :admin :enabled] true))))
(GET "/admin/disable" req (-> (found "/")
(assoc :session (assoc-in (:session req) [:user :admin :enabled] false)))))