Cloudron makes it easy to run web apps like WordPress, Nextcloud, GitLab on your server. Find out more or install now.


Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Bookmarks
  • Search
Skins
  • Light
  • Brite
  • Cerulean
  • Cosmo
  • Flatly
  • Journal
  • Litera
  • Lumen
  • Lux
  • Materia
  • Minty
  • Morph
  • Pulse
  • Sandstone
  • Simplex
  • Sketchy
  • Spacelab
  • United
  • Yeti
  • Zephyr
  • Dark
  • Cyborg
  • Darkly
  • Quartz
  • Slate
  • Solar
  • Superhero
  • Vapor

  • Default (No Skin)
  • No Skin
Collapse
Brand Logo

Cloudron Forum

Offical apps | Community apps | Demo | Docs | Install
  1. Cloudron Forum
  2. Package development
  3. HeCAPTe: a stateless, privacy-first CAPTCHA service you can embed almost anywhere.

HeCAPTe: a stateless, privacy-first CAPTCHA service you can embed almost anywhere.

Scheduled Pinned Locked Moved Package development
22 Posts 5 Posters 2.8k Views 6 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • girishG
    girishG
    girish
    Staff
    wrote on last edited by
    #3

    This is great, already have it running.

    1. git clone https://codeberg.org/TheMeerkat/HeCAPTe-Cloudron.git
    2. cloudron install --image codeberg.org/themeerkat/hecapte-cloudron:1.0.0
    3. Visited /admin and set a password
    4. Created a site id and secret key.
    5. <stuck here> . is there an example where I can copy/paste the wasm stuff needed?
    TheMeerkatT 1 Reply Last reply
    3
    • girishG girish

      This is great, already have it running.

      1. git clone https://codeberg.org/TheMeerkat/HeCAPTe-Cloudron.git
      2. cloudron install --image codeberg.org/themeerkat/hecapte-cloudron:1.0.0
      3. Visited /admin and set a password
      4. Created a site id and secret key.
      5. <stuck here> . is there an example where I can copy/paste the wasm stuff needed?
      TheMeerkatT
      TheMeerkatT
      TheMeerkat
      wrote on last edited by TheMeerkat
      #4

      Thanks so much! I appreciate it. 💖

      @girish said in HeCAPTe: a stateless, privacy-first CAPTCHA service you can embed almost anywhere.:

      1. <stuck here> . is there an example where I can copy/paste the wasm stuff needed?

      Documentation is definitely the weakest link right now, I think. Here's a cobbled-together example:
      EDIT: Slightly more coherent. Edited five minutes after posting.

      Form:

      <!-- ...existing code... -->
      <input type="hidden" id="hecapte-payload" name="hecapte_payload">
      <script>
        const SITE_KEY = "YOUR_SITE_KEY";
        const worker = new Worker("https://hecate.eris.host/static/worker.js");
        let solverReady = false;
      
        worker.onmessage = (e) => {
          const { type, payload } = e.data;
          if (type === "STATUS" && payload === "READY") solverReady = true;
          if (type === "RESULT") {
            document.getElementById("hecapte-payload").value = JSON.stringify(payload);
          }
        };
      
        async function solveHeCAPTe() {
          if (!solverReady) return;
          const resp = await fetch(`https://hecate.eris.host/challenge?site_key=${SITE_KEY}`);
          if (!resp.ok) return;
          const challenge = await resp.json();
          const msgId = Date.now();
          worker.postMessage({
            id: msgId,
            type: "SOLVE",
            payload: {
              salt: challenge.salt,
              ts: challenge.ts,
              n: challenge.diff.n,
              k: challenge.diff.k,
              nonceStart: 0
            }
          });
          worker.addEventListener("message", function handler(e) {
            const { id, type, payload } = e.data;
            if (id !== msgId || type !== "SOLVE_RESULT") return;
            worker.removeEventListener("message", handler);
            document.getElementById("hecapte-payload").value = JSON.stringify({
              site_key: SITE_KEY,
              data: {
                nonce: payload.nonce,
                salt: challenge.salt,
                ts: challenge.ts,
                diff: challenge.diff,
                sig: challenge.sig,
                sol: payload.solution
              }
            });
          });
        }
      
        window.addEventListener("load", solveHeCAPTe);
      </script>
      <!-- ...existing code... -->
      

      Super basic backend pseudo-code:

      payload = json.loads(form["hecapte_payload"])
      resp = requests.post("https://example.com/verify", json=payload, timeout=5)
      if resp.json().get("status") != "ok":
          return 403
      
      TheMeerkatT 1 Reply Last reply
      1
      • TheMeerkatT TheMeerkat

        Thanks so much! I appreciate it. 💖

        @girish said in HeCAPTe: a stateless, privacy-first CAPTCHA service you can embed almost anywhere.:

        1. <stuck here> . is there an example where I can copy/paste the wasm stuff needed?

        Documentation is definitely the weakest link right now, I think. Here's a cobbled-together example:
        EDIT: Slightly more coherent. Edited five minutes after posting.

        Form:

        <!-- ...existing code... -->
        <input type="hidden" id="hecapte-payload" name="hecapte_payload">
        <script>
          const SITE_KEY = "YOUR_SITE_KEY";
          const worker = new Worker("https://hecate.eris.host/static/worker.js");
          let solverReady = false;
        
          worker.onmessage = (e) => {
            const { type, payload } = e.data;
            if (type === "STATUS" && payload === "READY") solverReady = true;
            if (type === "RESULT") {
              document.getElementById("hecapte-payload").value = JSON.stringify(payload);
            }
          };
        
          async function solveHeCAPTe() {
            if (!solverReady) return;
            const resp = await fetch(`https://hecate.eris.host/challenge?site_key=${SITE_KEY}`);
            if (!resp.ok) return;
            const challenge = await resp.json();
            const msgId = Date.now();
            worker.postMessage({
              id: msgId,
              type: "SOLVE",
              payload: {
                salt: challenge.salt,
                ts: challenge.ts,
                n: challenge.diff.n,
                k: challenge.diff.k,
                nonceStart: 0
              }
            });
            worker.addEventListener("message", function handler(e) {
              const { id, type, payload } = e.data;
              if (id !== msgId || type !== "SOLVE_RESULT") return;
              worker.removeEventListener("message", handler);
              document.getElementById("hecapte-payload").value = JSON.stringify({
                site_key: SITE_KEY,
                data: {
                  nonce: payload.nonce,
                  salt: challenge.salt,
                  ts: challenge.ts,
                  diff: challenge.diff,
                  sig: challenge.sig,
                  sol: payload.solution
                }
              });
            });
          }
        
          window.addEventListener("load", solveHeCAPTe);
        </script>
        <!-- ...existing code... -->
        

        Super basic backend pseudo-code:

        payload = json.loads(form["hecapte_payload"])
        resp = requests.post("https://example.com/verify", json=payload, timeout=5)
        if resp.json().get("status") != "ok":
            return 403
        
        TheMeerkatT
        TheMeerkatT
        TheMeerkat
        wrote on last edited by TheMeerkat
        #5

        Sorry, it's 3:30AM where I am right now. I may not have been quite as clear as I intended.

        Basically, due to the ideal of being embeddable and invisible, there's no easy widget; implementations are semi-manual affairs, manually threaded through the thing you're protecting, with the HeCAPTe server's response processed by your own backend.

        Obviously, the ideal for adoptability and ease-of-use would be to create a bunch of pre-fab implementations (e.g., WordPress plugin and npm module), but I probably lack both the skill and the time to make these "quickly."

        For this specifically:

        is there an example where I can copy/paste the wasm stuff needed?

        /static/worker.js calls the .wasm module directly; you just need to invoke $HeCAPTeInstance/static/worker.js.

        1 Reply Last reply
        2
        • girishG
          girishG
          girish
          Staff
          wrote on last edited by
          #6

          @themeerkat yes, I got it going more . I used your example and changed the URLs - https://paste.cloudron.io/saruhogawi.xml . I had to upload the static things (solver, worker, wasm) into surfer . Then, some CORS into nginx (would be great if the hecapte server can have this configurable) and my test site loads. Something is up with /verify , checking what...

          TheMeerkatT 1 Reply Last reply
          2
          • girishG
            girishG
            girish
            Staff
            wrote on last edited by
            #7

            w00h00 . @themeerkat works 🙂 I was sending the /verify incorrectly to surfer instead of hecapte.

            image.png

            1 Reply Last reply
            4
            • girishG girish

              @themeerkat yes, I got it going more . I used your example and changed the URLs - https://paste.cloudron.io/saruhogawi.xml . I had to upload the static things (solver, worker, wasm) into surfer . Then, some CORS into nginx (would be great if the hecapte server can have this configurable) and my test site loads. Something is up with /verify , checking what...

              TheMeerkatT
              TheMeerkatT
              TheMeerkat
              wrote on last edited by TheMeerkat
              #8

              @girish said in HeCAPTe: a stateless, privacy-first CAPTCHA service you can embed almost anywhere.:

              Then, some CORS into nginx (would be great if the hecapte server can have this configurable)

              Definitely. There's next-to-no "easy" config right now; I have an informal checklist for changes I'd want to make before it goes from alpha to beta, and I'll make a note for CORS specifically.

              @girish said in HeCAPTe: a stateless, privacy-first CAPTCHA service you can embed almost anywhere.:

              w00h00 . @themeerkat works 🙂 I was sending the /verify incorrectly to surfer instead of hecapte.

              Awesome! 😻 Thanks so much for trying it out! I genuinely appreciate your feedback and testing. 😸

              1 Reply Last reply
              3
              • TheMeerkatT TheMeerkat

                HeCAPTe

                Humane, embeddable Cost-Asymmetric Proof-of-work Turing exam

                icon.png

                Hello! I was looking for a particular kind of self-hosted service I could use as my first Cloudron contribution: a privacy-first price-them-out CAPTCHA.

                I hate the usability/accessibility nightmare that are traditional CAPTCHAs, especially now that essentially every method can be outsmarted by a cheap local LLM model. There were some promising PoW-based alternatives (Capjs, ALTCHA, mCaptcha, etc.), which I conceptually loved, but all of them either used a simple SHA-256-based puzzle (which is elementary to spammers who already have a bot farm) or had some other disqualifying feature for my preferences.

                Necessity is the mother of invention, and so on, so I made my own!
                https://tangled.org/katsuricata.com/HeCAPTe

                It uses an Equihash-based puzzle (if you're unfamiliar, think of it as Argon2 but extremely cheap to verify) and no visible widget users need to interact with. It's completely invisible as anything other than a small processing delay, and its cookieless and stateless nature means you don't need to disclose it to comply with privacy law.

                I'll let the project's README speak for itself:

                HeCAPTe provides a stateless spam-prevention mechanism that respects user privacy. Unlike traditional CAPTCHAs that rely on tracking user behavior or forcing users to complete busywork, HeCAPTe requires the user’s system to solve a computational puzzle (Equihash). This “Proof-of-Work” approach makes it computationally expensive for bots to generate mass requests while remaining quick for legitimate human users on modern devices.

                • Humane: Requires no additional human interaction and presents no impediment to accessibility. Doesn’t try to extract value from the user by having them train image recognition models. Doesn’t infuriate vision-impaired users with audio from the first prototype of the telephone.
                • Embeddable: Requires nothing more than one small Go binary, a few static files (including the .wasm solver), and an SQLite database. Even the cheapest VPS can run it without a hitch.
                • Cost-Asymmetric: Expensive to solve, cheap to verify.
                • Proof-of-work: HeCAPTe uses Equihash, a memory-hard proof-of-work algorithm. Unlike simple SHA256-based puzzles, Equihash's memory requirements make it significantly more costly to solve at scale; you can’t just throw more GPUs at the problem and call it a day, but my phone solves the puzzles about as quickly as my gaming laptop.
                • Turing exam: Not quite a Turing test. Any one user submission is not, as per the original CAPTCHA vision, “proof” of humanity—but in a world with advanced OCR, services that have underpaid laborers type in answers for fractions of a penny, and even tiny local AI models that can easily solve most natural language puzzles, that vision is likely dead anyway.

                Don’t try to barricade the way for bots and stop humans along the way; just make it more expensive to spam you than they could possibly get back as profit.

                And then, since a Cloudron app was what I was trying to secure in the first place, packaging it for here just made the most sense.

                Now, extremely important warning:

                This should be considered ALPHA STATE SOFTWARE.

                I am not a professional programmer. I'm not even good at it. This is cobbled together with spit and broken dreams. I have verified that it works, doesn't cause any crazy disasters, that the Equihash logic is correct (for this simplified use case), that it has no neon-sign security holes, etc., but it's definitely missing basic comfort features I didn't personally care enough about to put in v1.0 and it hasn't exactly been through a battering ram of tests. Use this at your own risk!

                Demo

                The default demo page is up and running at https://hecate.eris.host/. Use the site ID ab2946a4e8af5dbaef82419450267ebd to test its default parameters. Now imagine it was a contact form, and "I am not a robot" was just labelled "Submit". I'd like to think that's a fair bit better of an experience than most security checks.

                Install

                Again: please see the bolded text about alpha state software.

                To install as a Community App, enter this when requested:
                https://mirror.tangled.network/xrpc/sh.tangled.git.temp.getBlob?path=CloudronVersions.json&ref=main&repo=did%3Aplc%3Apomgtubhgnuew7wmpwgk7dzd

                Contribute!

                Please give me feedback on how useful you'd find this and any obvious issues you see with it! This thread is the only place I'm really advertising this to start with. If any actual-developers-for-real want to offer code contributions to the Codeberg repositories, I'd basically cry from pure elation. It's FOSS software!

                Also, monetary support is never expected but always dearly appreciated.

                timconsidineT
                timconsidineT
                timconsidine
                App Dev
                wrote on last edited by
                #9

                @TheMeerkat awesome!
                Congratulations and thank you for the great work
                Looking forward to trying it out

                Indie app dev, huge fan of Cloudron PaaS, scratching my itches : communityapps.appx.uk

                1 Reply Last reply
                2
                • TheMeerkatT
                  TheMeerkatT
                  TheMeerkat
                  wrote on last edited by
                  #10

                  new! Updated to 1.0.1.

                  codeberg.org/themeerkat/hecapte-cloudron:1.0.1

                  I added customization options: renaming sites, deleting sites, and specifying CORS(!) on registration. This should make it a lot easier to use.

                  1 Reply Last reply
                  4
                  • TheMeerkatT
                    TheMeerkatT
                    TheMeerkat
                    wrote on last edited by TheMeerkat
                    #11

                    new! Updated to 1.0.2, after a hefty delay. Sorry about that.

                    I significantly improved the security of the project, most importantly. Not far behind, refactoring the entire /admin panel to be... well, an actual admin panel. It's been redone almost from the ground up for maintainability going forward. Finally, it's more resilient to OOM bugs in unlucky situations.

                    codeberg.org/themeerkat/hecapte-cloudron:1.0.2

                    Nope. Tested all of the local code to within an inch of its life; tested the Docker image locally; then watched as it completely shattered into splinters as I tried to update the demo site running on Cloudron. 💀 Good lesson to learn before I embarrass myself publicly, next time?

                    Please keep using 1.0.1 for right now (if anyone's using it at all). I need to sleep right now, but I'll take another look in the morning.

                    1 Reply Last reply
                    2
                    • jamesJ
                      jamesJ
                      james
                      Staff
                      wrote on last edited by
                      #12

                      Hello @themeerkat

                      With Cloudron 9.1 we have added community app support.
                      Please check the latest documentation for package publishing https://docs.cloudron.io/packaging/publishing
                      Could you update your repo to include these changes?

                      TheMeerkatT 1 Reply Last reply
                      2
                      • jamesJ james

                        Hello @themeerkat

                        With Cloudron 9.1 we have added community app support.
                        Please check the latest documentation for package publishing https://docs.cloudron.io/packaging/publishing
                        Could you update your repo to include these changes?

                        TheMeerkatT
                        TheMeerkatT
                        TheMeerkat
                        wrote on last edited by
                        #13

                        @james said:

                        Hello @themeerkat

                        With Cloudron 9.1 we have added community app support.
                        Please check the latest documentation for package publishing https://docs.cloudron.io/packaging/publishing
                        Could you update your repo to include these changes?

                        Done. Also, the issue with the previous version is now resolved!

                        To install it as a community app, use this link:
                        https://codeberg.org/TheMeerkat/HeCAPTe-Cloudron/raw/branch/main/CloudronVersions.json

                        1 Reply Last reply
                        6
                        • jamesJ
                          jamesJ
                          james
                          Staff
                          wrote on last edited by
                          #14

                          Hello @themeerkat
                          I have added your package to the list: https://forum.cloudron.io/topic/15172/community-apps

                          1 Reply Last reply
                          4
                          • TheMeerkatT
                            TheMeerkatT
                            TheMeerkat
                            wrote on last edited by
                            #15

                            Massive 2.0 update. Following SemVar, that means a breaking change, and... yeah, it's breaking all right!

                            I've consolidated the two repositories and made several improvements that did, unfortunately, invalidate existing installs; I figured it was best to do this now, while everything is still early. It does mean that updates of the old app are no longer possible, however. You will need to reinstall from scratch as a new community app with https://codeberg.org/TheMeerkat/HeCAPTe/raw/branch/main/CloudronVersions.json as the source file.

                            Sorry about this. It allowed for me to implement the requested aliasing, plus made it much easier for me to localize it (per a Codeberg issue) in the future. I won't have to do that again.

                            @james Could you update the link to the versions file in the masterlist, please?

                            luckowL 1 Reply Last reply
                            4
                            • jamesJ
                              jamesJ
                              james
                              Staff
                              wrote on last edited by
                              #16

                              Hello @themeerkat
                              I have updated both URLs and made you an editor for the detailed post https://forum.cloudron.io/post/121505
                              Now you can edit this one freely.

                              1 Reply Last reply
                              2
                              • TheMeerkatT TheMeerkat

                                Massive 2.0 update. Following SemVar, that means a breaking change, and... yeah, it's breaking all right!

                                I've consolidated the two repositories and made several improvements that did, unfortunately, invalidate existing installs; I figured it was best to do this now, while everything is still early. It does mean that updates of the old app are no longer possible, however. You will need to reinstall from scratch as a new community app with https://codeberg.org/TheMeerkat/HeCAPTe/raw/branch/main/CloudronVersions.json as the source file.

                                Sorry about this. It allowed for me to implement the requested aliasing, plus made it much easier for me to localize it (per a Codeberg issue) in the future. I won't have to do that again.

                                @james Could you update the link to the versions file in the masterlist, please?

                                luckowL
                                luckowL
                                luckow
                                translator
                                wrote on last edited by
                                #17

                                @TheMeerkat Woohoo! It works like a charm. Thank you so much for your work.

                                Pronouns: he/him | Primary language: German

                                1 Reply Last reply
                                2
                                • TheMeerkatT
                                  TheMeerkatT
                                  TheMeerkat
                                  wrote on last edited by
                                  #18

                                  The significantly improved v3.0.0 is out now!

                                  [3.0.0]

                                  • Moved the project home to https://tangled.org/katsuricata.com/HeCAPTe (from Codeberg) and the container image to Docker Hub (docker.io/katsuricata/hecapte).
                                  • Fixed browser-flow regressions that shipped in 2.0.0: the first-run setup page never loaded wasm_exec.js (so new Go() threw and setup could never complete through the UI), and the password page called bufferDecode/bufferEncode without loading admin.js. Added a template test that fails when a page uses new Go(), solveChallenge(), or bufferDecode/bufferEncode without loading the script that defines it.
                                  • Added an Equihash difficulty floor (crypto.MinN = 60). ValidateParams, tokens.GenerateChallenge, and VerifySolution all reject parameters below the floor, so no configuration path can turn the verifier into a free token oracle. The server warns loudly when the global preset or a site override uses low, and flags weak sites on the admin dashboard.
                                  • Added per-IP rate limiting (token bucket) on the unauthenticated admin endpoints: 10 req/min (burst 5) on the login/setup challenge fetches and 5 req/min (burst 2) on the login POST. Buckets key on the peer address and honor X-Forwarded-For only behind TRUST_PROXY=1.
                                  • Added security response headers: X-Content-Type-Options: nosniff, frame-ancestors 'none', X-Frame-Options: DENY, and Referrer-Policy: same-origin.
                                  • Added a one-time startup warning when X-Forwarded-Proto arrives but TRUST_PROXY is unset, turning a silent reverse-proxy misconfiguration into an observable one.
                                  • Upgraded modernc.org/sqlite from 1.55.0 to 1.56.0 (bundled SQLite C library; staying current is the only CVE mitigation).
                                  • Expired WebAuthn reauthentication tokens are now swept on each store, so the map cannot grow without bound.
                                  • Updated the README (difficulty floor, rate limiting, response headers, forwarded-header warning, project layout) and added/refreshed tests for every change.
                                  1 Reply Last reply
                                  1
                                  • TheMeerkatT
                                    TheMeerkatT
                                    TheMeerkat
                                    wrote on last edited by
                                    #19

                                    As a result of the first entry, the CloudronVersions.json link has changed:
                                    https://mirror.tangled.network/xrpc/sh.tangled.git.temp.getBlob?path=CloudronVersions.json&ref=main&repo=did%3Aplc%3Apomgtubhgnuew7wmpwgk7dzd

                                    I'll manually update the Codeberg one for a while, but you should change it at some point.

                                    TheMeerkatT 1 Reply Last reply
                                    1
                                    • jamesJ
                                      jamesJ
                                      james
                                      Staff
                                      wrote on last edited by
                                      #20

                                      Hello @themeerkat
                                      Maybe you want to add your app to the community app store?
                                      https://ca.cloudron.io/

                                      TheMeerkatT 1 Reply Last reply
                                      2
                                      • jamesJ james

                                        Hello @themeerkat
                                        Maybe you want to add your app to the community app store?
                                        https://ca.cloudron.io/

                                        TheMeerkatT
                                        TheMeerkatT
                                        TheMeerkat
                                        wrote on last edited by TheMeerkat
                                        #21

                                        @james had no idea that was a thing! thanks for the tip 😸

                                        https://ca.cloudron.io/app/hecapte

                                        1 Reply Last reply
                                        4
                                        • TheMeerkatT TheMeerkat

                                          As a result of the first entry, the CloudronVersions.json link has changed:
                                          https://mirror.tangled.network/xrpc/sh.tangled.git.temp.getBlob?path=CloudronVersions.json&ref=main&repo=did%3Aplc%3Apomgtubhgnuew7wmpwgk7dzd

                                          I'll manually update the Codeberg one for a while, but you should change it at some point.

                                          TheMeerkatT
                                          TheMeerkatT
                                          TheMeerkat
                                          wrote on last edited by
                                          #22

                                          TheMeerkat said:

                                          As a result of the first entry, the CloudronVersions.json link has changed:
                                          https://mirror.tangled.network/xrpc/sh.tangled.git.temp.getBlob?path=CloudronVersions.json&ref=main&repo=did%3Aplc%3Apomgtubhgnuew7wmpwgk7dzd

                                          I'll manually update the Codeberg one for a while, but you should change it at some point.

                                          actually, turns out I won't! good timing: 4.0.0 (and now 4.0.1) has breaking changes, so you should manually upgrade anyway.

                                          most notably: the secret key needs to be sent to the HeCAPTe server now, not just the public site key, bringing it in-line with other CAPTCHA services.

                                          1 Reply Last reply
                                          1
                                          • TheMeerkatT TheMeerkat referenced this topic on

                                          Hello! It looks like you're interested in this conversation, but you don't have an account yet.

                                          Getting fed up of having to scroll through the same posts each visit? When you register for an account, you'll always come back to exactly where you were before, and choose to be notified of new replies (either via email, or push notification). You'll also be able to save bookmarks and upvote posts to show your appreciation to other community members.

                                          With your input, this post could be even better 💗

                                          Register Login
                                          Reply
                                          • Reply as topic
                                          Log in to reply
                                          • Oldest to Newest
                                          • Newest to Oldest
                                          • Most Votes


                                          • Login

                                          • Don't have an account? Register

                                          • Login or register to search.
                                          • First post
                                            Last post
                                          0
                                          • Categories
                                          • Recent
                                          • Tags
                                          • Popular
                                          • Bookmarks
                                          • Search