This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2023-04-20
Channels
- # ai (1)
- # announcements (4)
- # babashka (61)
- # babashka-sci-dev (14)
- # biff (15)
- # calva (34)
- # clj-kondo (43)
- # clj-on-windows (1)
- # clojure (123)
- # clojure-europe (31)
- # clojure-nl (1)
- # clojure-norway (8)
- # clojure-uk (4)
- # clojurescript (12)
- # code-reviews (2)
- # community-development (9)
- # core-async (3)
- # datahike (4)
- # datomic (61)
- # events (1)
- # graphql (3)
- # hyperfiddle (155)
- # introduce-yourself (1)
- # lsp (64)
- # malli (10)
- # pathom (10)
- # reagent (5)
- # reitit (6)
- # shadow-cljs (2)
- # tools-build (2)
- # vim (8)
- # xtdb (3)
omg look under "recent news & activity" 😂 https://www.crunchbase.com/organization/biffa
A thread today on content sydication. Maybe interesting for PlatyPub. https://news.ycombinator.com/item?id=35636052
> automated syndication often sucks. The content ownership part is the truly important part. You can most definitely consider syndicating manually, in optimal form per social network
Each content type + channel has unique requirements. Clojure composition FTW?
Ah yes, indieweb stuff... An issue with automated syndication is that a lot of platforms don't even have open APIs, e.g. twitter's basically that way now, and the new substack notes thing has never had an API (and I'll be surprised if it ever does). But maybe could still be useful to have platypub support a copy&paste workflow
Also I discovered from that thread that I'm not the only person to think of the platypus pun! https://platypush.tech/
Haha, I saw that!
I might even try to script a copy/past flow with etaion or such. The main thing is it’s hard to wrap your head around a creative/content flow if all the production spots are scattered to all the walled gardens. I know that’s the way it is though. I’ve never used the social media schuler apps though, so not very experienced in this space. (still living in a web2.0 rss+api fantasy :face_in_clouds:)
As often happens when I'm stuck on something, I start typing out a question for Channel Biff and in the process end up pulling myself out of the mire. This time, however, instead of continuing on in silence, I think what I was struggling with might be worth sharing.
I'm working with the biff/authentication-plugin
to create a feature where, if folks are given a link to a part of the site requiring a log-in, they get diverted to the sign-in process, but once that's done, they're dumped right back where we found them. So someone following a link to "/fun/activity/" will end up on "/fun/activity/" after they sign in, and someone going to "/interesting/resource/" will end up at "/interesting/resource/" and so forth.
I'll post how I did this in the thread for those interested. I'm fairly new to all this, so I also wouldn't mind a gut check to see if I'm going about this in a reasonable way. I've stumbled a bit along the way, and I'm not fool enough to believe I'm done stumbling!

Our journey begins, like all journeys, in the middleware. Here's what I wrap around all the routes that should require a log-in:
(defn wrap-sign-in-required [handler]
(fn [{:keys [biff/db] {:keys [uid]} :session :as req}]
(if (some? uid)
(handler (assoc req :user (xt/entity db uid)))
{:status 303
:headers {"location" (str "/signin?return=" (:uri req))}})))
The signin-page
grabs the return
value out of the params and passes it along via the map in the :hidden
key in the biff/form
options. On submit, our user, their email, and the return url are all sent along to "/auth/send-code". This inside the Biff implementation, so what I figured I would do is intercept the two bits of info I need (the email to identify the user and the return url) with some middleware. Namely this:
(defn wrap-record-redirect
[handler]
(fn [{db :biff/db {:keys [return email]} :params :as req}]
(if (and return email)
(let [r-id (biff/lookup-id db :auth.redirect/email email)]
(biff/submit-tx
req
[{:db/op :merge
:db/doc-type :auth.redirect
:xt/id (or r-id :)
:auth.redirect/email email
:auth.redirect/url return}])
(handler req))
(handler req))))
I enacted a few embarrassingly complicated plans to get that in front of the biff/authentication-plugin
routes, until I actually looked at how Biff assembled the routes, realized I could just update
the biff/authentication-plugin
like it's a map because that's what it is. Something like this:
(update (biff/authentication-plugin {:biff.auth/app-path "/signed-in"
:biff.auth/new-user-tx new-user-tx})
:routes #(into ["" {:middleware [mid/wrap-record-redirect]}] %))
Oh, and I fed the plugin's :biff.auth/app-path
a route to this handler:
(defn signed-in
[{:keys [biff/db user]}]
(if-let [redirect (biff/lookup db :auth.redirect/email (:user/email user))]
(ring.util.response/redirect (str (:auth.redirect/url redirect)))
(ring.util.response/redirect "/")))
And this seems to have done it! I'm sure there's easier ways to have done some of this stuff, but I learned a lot along the way, and I'm feeling pretty smug about that.Nice! FYI you may have had an easier time by copy and pasting the https://github.com/jacobobryant/biff/blob/master/src/com/biffweb/impl/auth.clj into a new namespace in your project and then make any changes there. e.g. then instead of creating a new redirect document you can just add the redirect URL to the :biff.auth/code document: https://github.com/jacobobryant/biff/blob/master/src/com/biffweb/impl/auth.clj#L178. also could make handling the actual redirect simpler.
(Actually for signing in via code, maybe no need to store the redirect URL in the DB at all? I think you can just keep it in the form params, similar to how the user's email address is stored.)
Also FYI: there is a small vulnerability here since the signin page takes an arbitrary redirect URL. e.g. someone could do
, so after the user signs in they get taken to a different website. Realistically it's unlikely that would become an issue for a small app, but at a minimum it wouldn't hurt to check the redirect URL with something like (= (:host (lambdaisland.uri/uri redirect-url)) (:biff/base-url ctx))
(see https://cheatsheetseries.owasp.org/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html)
Oh, that's good to know. Checking the redirect URL should be easy enough.
I'm going to bask in the glory of this success for a little bit longer and then probably do that copy and paste trick, because that seems a bit more clean and maintainable.