Skip to content

A cloud backup solution that employs the "ChaCha20 + Serpent-256 CBC + HMAC-SHA3-512" authenticated encryption scheme for data encryption and ML-KEM-1024 for quantum-resistant key exchange.

License

Notifications You must be signed in to change notification settings

Northstrix/plum-cave

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

28 Commits
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Plum Cave

A cloud backup solution that employs the "ChaCha20 + Serpent-256 CBC + HMAC-SHA3-512" authenticated encryption scheme for data encryption and ML-KEM-1024 for quantum-resistant key exchange.

Check it out at https://plum-cave.netlify.app/

SourceForge page: https://sourceforge.net/projects/plum-cave/

ChaCha20 + Twofish-256 CBC + HMAC-SHA3-512 Version: https://sourceforge.net/projects/plum-cave-twofish/

The account password can contain non-ASCII characters!

The app is fully localized into:

✓ English

✓ Hebrew

✓ Argentinian Spanish

Hovered element in the desktop features section

Dropzone

Web app dashboard 2560px

Web app dashboard 1322px

Python script overview

Firestore Rules

rules_version = '2';
service cloud.firestore {
  match /databases/{database}/documents {

    // === 1. /data/{userEmail}/backups, limit to 10 backups ===
    match /data/{userEmail}/backups/{backupId} {
      allow get, list: if resource.data.isPublic == true
                       || (request.auth != null && request.auth.token.email == userEmail);

      allow update: if resource.data.isPublic == true
        && request.resource.data.diff(resource.data).affectedKeys().hasOnly(['downloads'])
        && request.resource.data.downloads == resource.data.downloads + 1;

      allow create: if request.auth != null
        && request.auth.token.email == userEmail
        && (
          !exists(/databases/$(database)/documents/data/$(userEmail)/backups)
          || get(/databases/$(database)/documents/data/$(userEmail)/backups).list().size() < 10
        );
      allow update, delete: if request.auth != null && request.auth.token.email == userEmail;
    }

    // === 1b. Allow owner full access to all subcollections and docs under each backup ===
    match /data/{userEmail}/backups/{backupId}/{document=**} {
      allow read, write, delete: if request.auth != null && request.auth.token.email == userEmail;
      allow get, list: if exists(/databases/$(database)/documents/data/$(userEmail)/backups/$(backupId))
        && get(/databases/$(database)/documents/data/$(userEmail)/backups/$(backupId)).data.isPublic == true;
    }

    // === 2. /data/{userEmail}/receivedBackups/{document=**} ===
    match /data/{userEmail}/receivedBackups/{document=**} {
      allow write: if request.auth != null; // Any authenticated user 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 (even unauthenticated) can read
      allow write, delete: if request.auth != null && request.auth.token.email == userEmail; // Only owner can write/delete
    }

    // === 4. /data/{userEmail}/private/encrypted/projectInfo, limit to 2 folders ===
    match /data/{userEmail}/private/encrypted/projectInfo/{projectId} {
      allow create: if request.auth != null && request.auth.token.email == userEmail
        && (
          !exists(/databases/$(database)/documents/data/$(userEmail)/private/encrypted/projectInfo)
          || get(/databases/$(database)/documents/data/$(userEmail)/private/encrypted/projectInfo).list().size() < 2
        );
      allow read, update, delete: if request.auth != null && request.auth.token.email == userEmail;
    }

    // === 5. /data/{userEmail}/private/encrypted/projectInfo/{projectId}/backups, limit to 5 per project ===
    match /data/{userEmail}/private/encrypted/projectInfo/{projectId}/backups/{backupId} {
      allow create: if request.auth != null && request.auth.token.email == userEmail
        && (
          !exists(/databases/$(database)/documents/data/$(userEmail)/private/encrypted/projectInfo/$(projectId)/backups)
          || get(/databases/$(database)/documents/data/$(userEmail)/private/encrypted/projectInfo/$(projectId)/backups).list().size() < 5
        );
      allow read, update, delete: if request.auth != null && request.auth.token.email == userEmail;
    }

    // === 6. /data/{userEmail}/private/{document=**} ===
    match /data/{userEmail}/private/{document=**} {
      allow read, write, delete: if request.auth != null && request.auth.token.email == userEmail;
    }

    // === 7. /data/{userEmail}/private root ===
    match /data/{userEmail}/private {
      allow read: if request.auth != null;
      allow write, delete: if request.auth != null && request.auth.token.email == userEmail;
    }

    // === 8. Default deny ===
    match /{document=**} {
      allow read, write, delete: if false;
    }
  }
}

Adjusting/Removing Limitations

Firestore rules are easy to edit, especially using AI tools like Perplexity or Mistral's Le Chat, so I'll only explain how to remove the in-app-enforced limitations.


Adjusting Project Limit
To modify maximum allowed projects per user:

  1. find if (projectsSnapshot.size >= 2) { line in Dashboard.tsx file
  2. Replace 2 with your desired limit
  3. To remove the project limit entirely:
    • Delete the entire if block
    • Remove its corresponding else statement wrapper
    • Retain internal code
    • Delete closing } for the block

Modifying Backup Limits
To adjust maximum allowed backups per project:

  1. Find if (backupsSnapshot.size >= 5) { line in Dashboard.tsx file

  2. Change 5 to preferred threshold

  3. To eliminate the backup limit: Remove the entire conditional block (

       if (backupsSnapshot.size >= 5) {
         const errorMessage = `
           <p style="margin-bottom: 10px;" dir="${isRTL ? 'rtl' : 'ltr'}">${t('backup_limit_reached_message')}</p>
           <p dir="${isRTL ? 'rtl' : 'ltr'}">${t('delete_backup_to_add_new')}</p>`;
         showErrorModal(errorMessage);
         return;
       }
    

Setting Up the App

To run the app with your own Firebase instance:

  1. Create a web app in Firebase

  2. Copy the database access credentials and paste them into app/lib/firebase.ts, replacing the mock-up credentials

  3. Enable the "Authentication" and "Firestore Database" services

  4. Configure Firestore Database rules

  5. Compile the web app

  6. Host the statically-compiled app on Netlify or any hosting of your choice

Credit

The existence of this project (at least in its current form) wouldn't've been possible without the following:

Web App

View transitions - Demo by Stefan Judis

Toolbars With Sliding Selection by Jon Kantner

Gsap Slider by Yudiz Solutions Limited

BUTTONS by TAYLOR

glowy hover effect by Ines

Counter by ANIMATA

Spotlight Card by HextaUI

Free Security Animation by DE GUZMAN, Jalei

Free Lock-Key_Animation Animation by Abdul Latif

Free Uploading to cloud Animation by Nazar

Free Share icon waiting Animation by jjjoven

Text scroll and hover effect with GSAP and clip by Juxtopposed

tabler-icons by tabler

lucide by lucide-icons

react-toastify by Fadi Khadra

sweetalert2 by sweetalert2

react-i18next by i18next

hash-wasm by Daninet

firebase-js-sdk by firebase

mipher by mpaland

crystals-kyber-js by dajiaji

File Upload by Aceternity UI

Balatro by React Bits

Animated Tooltip by Aceternity UI

Custom Progress Bar by Florin Pop

すりガラスなプロフィールカード by あしざわ - Webクリエイター

Signup Form from Aceternity UI

CSS table by Andrew Lohman

motion by motiondivision

GSAP by greensock

ogl by oframe

Bouncing Cube Loader by Haja Randriakoto

JTB studios - Link by Nico

Perplexity

Mistral's Le Chat

Used Namer UI components:

  • Halomot Button

  • Fancy Hero Section

  • Pricing Card

  • Fancy Navbar

  • Dreamy Input

  • Structured Block

  • Unfolding Sidebar

  • Random Number Generator

  • File Encrypter

Python Script

Replit Agent

Perplexity

Mistral's Le Chat

About

A cloud backup solution that employs the "ChaCha20 + Serpent-256 CBC + HMAC-SHA3-512" authenticated encryption scheme for data encryption and ML-KEM-1024 for quantum-resistant key exchange.

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published