108 lines
4.7 KiB
Clojure
108 lines
4.7 KiB
Clojure
(ns auto-ap.ssr.auth
|
|
(:require
|
|
[auto-ap.session-version :as session-version]
|
|
[auto-ap.ssr.hx :as hx]
|
|
[auto-ap.ssr.svg :as svg]
|
|
[buddy.sign.jwt :as jwt]
|
|
[config.core :refer [env]]
|
|
[hiccup2.core :as hiccup]
|
|
[hiccup.util :as hu]))
|
|
|
|
(defn logout [request]
|
|
{:status 301
|
|
:headers {"Location" "/login"}
|
|
:session {}})
|
|
|
|
(defn impersonate [request]
|
|
{:status 200
|
|
:session {:identity (dissoc (jwt/unsign (get-in request [:query-params "jwt"])
|
|
(:jwt-secret env)
|
|
{:alg :hs512})
|
|
:exp)
|
|
:version session-version/current-session-version}})
|
|
|
|
(defn login-url
|
|
([] (login-url nil))
|
|
([next]
|
|
|
|
(let [client-id "264081895820-0nndcfo3pbtqf30sro82vgq5r27h8736.apps.googleusercontent.com"
|
|
redirect-uri (str (:base-url env) "/api/oauth")]
|
|
(str (hu/url "https://accounts.google.com/o/oauth2/auth"
|
|
(cond-> {"access_type" "online"
|
|
"client_id" client-id
|
|
"redirect_uri" redirect-uri
|
|
"response_type" "code"
|
|
"max_auth_age" "0"
|
|
"scope" "https://www.googleapis.com/auth/userinfo.email https://www.googleapis.com/auth/userinfo.profile"}
|
|
next (assoc "state" (hu/url-encode next))))))))
|
|
|
|
(defn- login-page [contents]
|
|
{:status 200
|
|
:headers {"Content-Type" "text/html"}
|
|
:body (str "<!DOCTYPE html>"
|
|
(hiccup/html
|
|
[:html
|
|
[:head
|
|
[:meta {:charset "utf-8"}]
|
|
[:meta {:name "viewport" :content "width=device-width, initial-scale=1"}]
|
|
[:title "Integreat · Sign In"]
|
|
[:link {:rel "icon" :type "image/png" :href "/favicon.png"}]
|
|
[:link {:rel "stylesheet" :href "/output.css"}]
|
|
[:script {:defer true :src "https://cdn.jsdelivr.net/npm/alpinejs@3.x.x/dist/cdn.min.js"}]
|
|
[:style
|
|
"body{background:linear-gradient(160deg,#79b52e 0%,#009cea 100%);min-height:100vh}"]]
|
|
[:body contents]]))})
|
|
|
|
(defn- page-contents [request]
|
|
[:div
|
|
{:x-data (hx/json {:showError false
|
|
:errorDetails ""})
|
|
"@htmx:response-error.camel" "errorDetails = $event.detail.xhr.response; showError=true;"}
|
|
|
|
[:div.fixed.top-0.left-0.right-0.z-50.mx-auto.max-w-md.w-full.px-4.pt-6
|
|
{:x-show "showError"
|
|
"x-transition:enter" "transition duration-200 ease-out"
|
|
"x-transition:enter-start" "opacity-0 -translate-y-3"
|
|
"x-transition:enter-end" "opacity-100 translate-y-0"}
|
|
[:div.relative.bg-white.rounded-xl.shadow-xl.border.border-red-200.p-4
|
|
[:button.absolute.right-3.top-3.p-1.text-red-400.hover:text-red-600
|
|
{"@click" "showError=false"}
|
|
svg/filled-x]
|
|
[:div.flex.items-start.gap-3
|
|
[:div.flex-shrink-0.w-5.h-5.text-red-500 svg/alert]
|
|
[:div.flex-1.min-w-0
|
|
[:p.text-sm.font-medium.text-gray-900 "Something went wrong"]
|
|
[:p.text-xs.text-gray-500.mt-0.5
|
|
"Our team has been notified. Please try again."
|
|
[:span {:x-data (hx/json {"e" false})}
|
|
" "
|
|
[:a.text-xs.underline.cursor-pointer.text-gray-500.hover:text-gray-700
|
|
{"@click" "e=true"}
|
|
"Details"]
|
|
[:pre.text-xs.mt-1.font-mono.text-red-600.bg-red-50.p-2.rounded {:x-show "e" :x-text "errorDetails"}]]]]]]]
|
|
|
|
[:div.flex.items-center.justify-center.min-h-screen.px-4
|
|
[:div.w-full.max-w-lg
|
|
[:div.flex.flex-col.items-center.mb-10
|
|
[:img {:src "/img/logo-big.png" :alt "Integreat" :class "h-16 brightness-0 invert"}]]
|
|
|
|
[:div.bg-white.rounded-2xl.shadow-2xl.p-10
|
|
{:style "animation: slideUp 0.4s ease-out forwards; opacity: 0;"}
|
|
[:div.flex.flex-col.items-center.gap-8
|
|
[:div.text-center
|
|
[:h1.text-2xl.font-bold.text-gray-900 "Sign in to Integreat"]
|
|
[:p.mt-2.text-base.text-gray-500 "Use your Google account to continue"]]
|
|
|
|
[:a {:href (login-url (get (:query-params request) "redirect-to"))
|
|
:class "w-full max-w-xs flex items-center justify-center gap-3 px-6 py-3.5 text-base font-semibold rounded-xl border-2 border-gray-200 text-gray-700 bg-white hover:bg-gray-50 hover:border-gray-300 shadow-md hover:shadow-lg focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-gray-400 transition-all duration-150"}
|
|
svg/google
|
|
"Sign in with Google"]]
|
|
|
|
[:p.mt-2.text-center.text-xs.text-gray-400
|
|
"By signing in, you agree to our "
|
|
[:a.underline.hover:text-gray-600 {:href "/terms"} "Terms of Service"]
|
|
" and "
|
|
[:a.underline.hover:text-gray-600 {:href "/privacy"} "Privacy Policy"]]]]]])
|
|
|
|
(defn login [request]
|
|
(login-page (page-contents request))) |