jacobobryant / biff

A Clojure web framework for solo developers.
https://biffweb.com
MIT License
832 stars 40 forks source link

Provide postal and altcha utilities as alternatives to reCAPTCHA and Mailersend #223

Closed mjholub closed 3 days ago

mjholub commented 2 weeks ago

Hello, I'd be interested in developing functionality that abstracts the common boilerplate of setting up an altcha endpoint and a postal-based mailer for auth.

Altcha is a proof-of-work, puzzle-free method of detecting bots, that still allows controlled machine traffic to APIs, is fully open source, self-hostable and GDPR compliant. Similarly, while 3rd party mailer services might be convenient, not everyone wants to deal with vendor lock-ins, unfavorable ToS or pricing changes, privacy and free software ethics concerns etc.

Let me know if this aligns with the project's goals.

jacobobryant commented 2 weeks ago

Nice--Postal link for posterity (I hadn't seen it before).

I'd recommend starting out with a regular how-to guide, plus a standalone helper library if needed. For replacing MailerSend with Postal, you just need to instruct people how to edit their src/com/example/email.clj file and replace send-mailersend with a custom function.

You can also replace Recaptcha while still using the current authentication module as-is, although it requires a bit of a workaround. The module skips Recaptcha validation if :recaptcha/secret-key isn't present in resources/config.edn, so you can instruct people to remove that/leave it unset. Second, you can set the :biff.auth/email-validator option to a custom function that both validates the email (e.g. makes sure it has a @ in it, that kind of thing) and does the Altcha verification. Something like this:

diff --git a/starter/src/com/example.clj b/starter/src/com/example.clj
index 63fafb1..b0eaae6 100644
--- a/starter/src/com/example.clj
+++ b/starter/src/com/example.clj
@@ -15,9 +15,15 @@
             [nrepl.cmdline :as nrepl-cmd])
   (:gen-class))

+(defn auth-request-valid? [ctx email]
+  (and email
+       (re-matches #".+@.+\..+" email)
+       (not (re-find #"\s" email))
+       (passed-altcha? ctx)))
+
 (def modules
   [app/module
-   (biff/authentication-module {})
+   (biff/authentication-module {:biff.auth/email-validator auth-request-valid?})
    home/module
    schema/module
    worker/module])

And then include instructions for editing home.clj so it sets up the Altcha test.

A slight downside of this approach is that if the captcha test fails, the authentication module will include error=invalid-email in the redirect's query params instead of error=recaptcha like usual. So when showing the user an error message, you wouldn't be able to say whether it failed due to an actually invalid email or because of the captcha test. To remedy that, I'll update the authentication module so it takes another option (something like :biff.auth/captcha-fn), and then you can use that instead of overriding :biff.auth/email-validator).