Skip to content

Cryptographically reinforced form builder that utilizes ML-KEM-1024, as well as the "ChaCha20 + Serpent-256 CBC + HMAC-SHA3-512" authenticated encryption scheme to enable end-to-end encryption for enhanced data protection.

License

Notifications You must be signed in to change notification settings

Northstrix/blueberry-loom

Repository files navigation

Blueberry Loom

Cryptographically reinforced form builder that utilizes ML-KEM-1024, as well as the "ChaCha20 + Serpent-256 CBC + HMAC-SHA3-512" authenticated encryption scheme to enable end-to-end encryption for enhanced data protection.

Check it out at https://blueberry-loom.netlify.app/

You can set a password that contains non-ASCII characters.

The article about how this web app was built and how it works—including the part that covers the cryptographic mechanisms ensuring only the intended recipient is capable of decrypting a submitted response, and explaining how it came to be that way—is available at https://medium.com/@Northstrix/creating-a-form-builder-powered-by-advanced-cryptography-d1e827a6ddd5

SourceForge page with the version of the app where forms can be accessed using dedicated links instead of tags https://sourceforge.net/projects/blueberry-loom/

The app is localized into the following languages:

  • English
  • Hebrew (some inscriptions Latinized)
  • Latin American Spanish
  • German
  • French
  • Italian
  • Brazilian Portuguese
  • Polish
  • Cantonese

Alt Hero section Alt Hero section with language selector Alt Features section Alt Part of the landing page with MacBook Alt Form Builder Alt Dashboard Alt Footer

How to run

I assume you already have Node.js and npm installed.

  1. Clone the repository using the command:

    git clone https://github.com/Northstrix/blueberry-loom
    
  2. Open the project:

    • Open the cloned folder in VS Code or any IDE of your choice.
  3. Configure Firebase:

    • Open app/lib/firebase.ts file.
    • Create a Firebase instance with Authentication and Firestore Database enabled.
    • Create a new web app in the Firebase instance.
    • Replace the mock credentials in firebase.ts with your actual Firebase credentials and save the file.
  4. Set Firestore rules:

    • Apply the following rules to your Firestore database:

        rules_version = '2';
        service cloud.firestore {
          match /databases/{database}/documents {
        
            // === 1. /data/{userEmail}/forms/{formId} ===
            match /data/{userEmail}/forms/{formId} {
              // Allow anyone to increment visits or responses by +1, but only if form is public
              allow update: if (
                resource.data.isPublic == true &&
                (
                  (request.resource.data.diff(resource.data).affectedKeys().hasOnly(['visits']) && request.resource.data.visits == resource.data.visits + 1) ||
                  (request.resource.data.diff(resource.data).affectedKeys().hasOnly(['responses']) && request.resource.data.responses == resource.data.responses + 1)
                )
              );
        
              // Allow get/list if public, or if the user is the owner and email is verified
              allow get, list: if resource.data.isPublic == true
                || (request.auth != null && request.auth.token.email == userEmail && request.auth.token.email_verified == true);
        
              // Allow create, update, delete only if the user is the owner and email is verified
              allow create, update, delete: if request.auth != null && request.auth.token.email == userEmail && request.auth.token.email_verified == true;
            }
        
            // === 1b. /data/{userEmail}/forms/{formId}/{document=**} ===
            match /data/{userEmail}/forms/{formId}/{document=**} {
              // Owner (with verified email) can read/write/delete
              allow read, write, delete: if request.auth != null && request.auth.token.email == userEmail && request.auth.token.email_verified == true;
        
              // Anyone can get/list if parent form is public
              allow get, list: if exists(/databases/$(database)/documents/data/$(userEmail)/forms/$(formId))
                && get(/databases/$(database)/documents/data/$(userEmail)/forms/$(formId)).data.isPublic == true;
            }
        
            // === 2. /data/{userEmail}/receivedResponses/{document=**} ===
            match /data/{userEmail}/receivedResponses/{document=**} {
              allow write: if true; // Anyone (including non-authenticated users) can write
              allow read, delete: if request.auth != null && request.auth.token.email == userEmail; // Only owner can read/delete
            }
        
            // === 2b. /data/{userEmail}/receivedBackups/{document=**} ===
            match /data/{userEmail}/receivedBackups/{document=**} {
              allow write: if true; // Anyone (including non-authenticated users) can write
              allow read, delete: if request.auth != null && request.auth.token.email == userEmail; // Only owner can read/delete
            }
        
            // === 3. /data/{userEmail}/public/{document=**} ===
            match /data/{userEmail}/public/{document=**} {
              allow read: if true; // Anyone can read
              allow write, delete: if request.auth != null && request.auth.token.email == userEmail; // Only owner can write/delete
            }
        
            // === 4. /data/{userEmail}/private/encrypted/formData/all/keys/{uniqueFormId} ===
            match /data/{userEmail}/private/encrypted/formData/all/keys/{uniqueFormId} {
              // Only owner with verified email can write/read
              allow create, read, update, delete: if request.auth != null && request.auth.token.email == userEmail && request.auth.token.email_verified == true;
            }
        
            // === 5. /data/{userEmail}/private/{document=**} ===
            match /data/{userEmail}/private/{document=**} {
              // Any authenticated user can read/write/delete their own private route (regardless of email verification)
              allow read, write, delete: if request.auth != null && request.auth.token.email == userEmail;
            }
        
            // === 6. /data/{userEmail}/private root ===
            match /data/{userEmail}/private {
              allow read, write, delete: if request.auth != null && request.auth.token.email == userEmail;
            }
        
            // === 7. Default deny ===
            match /{document=**} {
              allow read, write, delete: if false;
            }
          }
        }
      
  5. Install dependencies by running:

    npm install
    
  6. Start the development server with:

    npm run dev
    
  7. If you want to have the ability to share the forms by distributing their links - Set up the form loader

    7.1. Repalce the form loader base URL within this app with your own (Ctrl + Shift + F -> https://blueberry-loom-form-loader.netlify.app)

Credit

Text Rotate by fancy components

motion by motiondivision

GSAP by greensock

Sign In by HextaUI

Chronicle Button by Haaguitos

Input Floating Label animation by Elpeeda

react-toastify by Fadi Khadra

sweetalert2 by sweetalert2

react-i18next by i18next

hash-wasm by Daninet

firebase-js-sdk by firebase

mipher by mpaland

BUTTONS by TAYLOR

Bento Grid by Aceternity UI

lucide by lucide-icons

Shining Text by HextaUI

Radix Checkbox by Animate UI

Custom Checkbox by Edil Ozi

チェックしないと押せないボタン by あしざわ - Webクリエイター

Help Button by LN

DraggableList by HextaUI

Haiku by DavidHDev

Dot Loader by PaceUI

UZUMAKI by Jules

Parallax Floating by fancy components

Glowing Effect by Aceternity UI

Card Spotlight by Aceternity UI

Canvas Reveal Effect by Aceternity UI

Fey.com Macbook Scroll by Aceternity UI

Tranquiluxe by UV Canvas

Animated Tooltip by Aceternity UI

Wheel Picker by Chánh Đại

React Wheel Picker by Chánh Đại

Resizable Navbar by Aceternity UI

Menu Vertical by Berlix UI

Perplexity

About

Cryptographically reinforced form builder that utilizes ML-KEM-1024, as well as the "ChaCha20 + Serpent-256 CBC + HMAC-SHA3-512" authenticated encryption scheme to enable end-to-end encryption for enhanced data protection.

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published