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

Apps | Demo | Docs | Install
  1. Cloudron Forum
  2. App Packaging & 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 App Packaging & Development
9 Posts 3 Posters 31 Views 3 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.
  • TheMeerkatT Offline
    TheMeerkatT Offline
    TheMeerkat
    wrote last edited by TheMeerkat
    #1

    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://codeberg.org/TheMeerkat/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.
    https://codeberg.org/TheMeerkat/HeCAPTe-Cloudron

    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 74fb05ab4ec13d50938b67d9e2d2de21 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. You'll need the Cloudron CLI for this.

    cloudron install --image codeberg.org/themeerkat/hecapte-cloudron:1.0.0
    

    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 1 Reply Last reply
    4
    • girishG Do not disturb
      girishG Do not disturb
      girish
      Staff
      wrote last edited by
      #2

      I am not a professional programmer. I'm not even good at it.

      Wow, that is quite some tremendous work, if that's what you consider yourself 🙂

      1 Reply Last reply
      1
      • girishG Do not disturb
        girishG Do not disturb
        girish
        Staff
        wrote 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
        1
        • 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 Offline
          TheMeerkatT Offline
          TheMeerkat
          wrote 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
          0
          • 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 Offline
            TheMeerkatT Offline
            TheMeerkat
            wrote 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
            0
            • girishG Do not disturb
              girishG Do not disturb
              girish
              Staff
              wrote 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
              1
              • girishG Do not disturb
                girishG Do not disturb
                girish
                Staff
                wrote last edited by
                #7

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

                image.png

                1 Reply Last reply
                1
                • 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 Offline
                  TheMeerkatT Offline
                  TheMeerkat
                  wrote 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
                  0
                  • 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://codeberg.org/TheMeerkat/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.
                    https://codeberg.org/TheMeerkat/HeCAPTe-Cloudron

                    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 74fb05ab4ec13d50938b67d9e2d2de21 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. You'll need the Cloudron CLI for this.

                    cloudron install --image codeberg.org/themeerkat/hecapte-cloudron:1.0.0
                    

                    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 Online
                    timconsidineT Online
                    timconsidine
                    App Dev
                    wrote last edited by
                    #9

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

                    1 Reply Last reply
                    1
                    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