Skip to content

Repository files navigation

Locknote

A private way to say what matters.

Locknote is a zero-knowledge, self-destructing note-sharing application. It encrypts each note in the browser before upload, stores encrypted envelopes only, and gives the sender control over expiry, burn-on-read delivery, dead switches, file sharing, receipts, and remote withdrawal.

Node.js React Supabase Vercel Quality gate

Evaluation at a glance

Locknote is documented and tested as a complete submission rather than a visual prototype. The material below maps directly to the evaluation criteria.

Evaluation criterion Review-ready evidence
Problem Understanding & Core Functionality Browser-side encryption, fragment-keyed sharing, burn-on-read, expiry, remote withdrawal, encrypted files, optional encrypted recipient replies, and delivery receipts.
Innovation & Meaningful Differentiation Proof-based delivery acknowledgements, private one-use encrypted-file leases, opt-in encrypted replies, Guardian Wipe threshold revocation, dead switches, seal fingerprints, and pre-seal realtime collaboration.
Technical Implementation & Architecture React/Vite client, Web Crypto API, Express/Zod/Helmet API, Supabase Auth and owner-only RLS account tables, Vercel functions, static CSP, and typed tests.
User Experience & Accessibility Intentional compose-to-share workflow, theme support, session-aware protected routes, keyboard command palette, skip link, semantic controls, responsive views, actionable errors, and automated axe checks.
Performance & Reliability / Demo Quality Health/version readiness, request IDs and safe timing telemetry, validation, rate limits, protected maintenance, bundle budget, live smoke test, and automated CI.
Documentation & Explanation This README plus dedicated evaluation, demo, architecture, security, API, testing, comparison, and environment guides.

Start with the Evaluation Guide for a rubric-by-rubric explanation, then use DEMO.md for a repeatable evaluator walkthrough.

Interface

Locknote composer in light mode

Locknote composer in dark mode

Locknote’s private-correspondence interface in light and dark themes.

Product experience gallery

GitHub-authenticated personal profile and vault

Locknote GitHub-authenticated profile showing verified identity, editable research bio, vault contacts, and local security statistics

After GitHub sign-in through Supabase Auth, Locknote presents a personalized identity view with the provider avatar, username, email, an opt-in private account bio, and a route to the user's browser-local vault. The bio and contact usernames are protected by owner-only Supabase row-level security; the vault summary keeps sender controls and tracked link status easy to find without creating a server-side plaintext archive.

QR-assisted secure delivery

Locknote sealed-delivery screen showing a private link, fragment-key explanation, seal fingerprint, QR code, expiry policy, and withdrawal control

The delivery screen makes the privacy model understandable at the point of sharing. It provides a copyable private link, policy badges, a human-verifiable seal fingerprint, browser-native sharing where available, a remote-withdrawal control, and a QR code for opening the full link on another intended device.

The QR code represents the full private share URL, including its fragment-held decryption material. Treat it with the same care as the copied link and show it only to the intended recipient.

For a detailed feature-by-feature explanation and privacy boundary, see the Feature Guide.

GitHub authentication to personal vault flow

flowchart LR
    A[User selects\nContinue with GitHub] --> B[Supabase Auth\nstarts OAuth]
    B --> C[GitHub\nverifies identity]
    C --> D[Supabase callback\ncreates browser session]
    D --> E[Locknote /auth/callback\nexchanges PKCE session]
    E --> F[Private account profile\nprovider identity + opt-in bio]
    F --> G[Browser-local vault\ntracked links, receipts, withdrawal]

    B -. GitHub client secret remains in Supabase .-> H[Supabase provider settings]
    G -. plaintext never added to vault records .-> I[Encrypted envelope lifecycle]

    classDef trusted fill:#e8f5ef,stroke:#247a56,color:#173f30,stroke-width:1.5px;
    classDef local fill:#f4edff,stroke:#7958a8,color:#3e275e,stroke-width:1.5px;
    classDef external fill:#fff4dd,stroke:#b7791f,color:#6d4508,stroke-width:1.5px;
    class A,F,G local;
    class B,D,H trusted;
    class C external;
    class E,I trusted;
Loading

This flow keeps responsibilities clear: GitHub verifies identity, Supabase manages OAuth, the browser session, and owner-only profile/contact rows, and Locknote presents a browser-local capability vault without storing note plaintext, keys, share URLs, or owner tokens in a profile record.

Demo

Resource Link
Live application https://lock-note-sigma.vercel.app/
Video walkthrough Watch the final evaluator walkthrough on Google Drive — a 2:47 narrated walkthrough of the live product, GitHub evidence, and Supabase schema.
Evaluator demo script docs/DEMO.md
Rubric evidence guide docs/EVALUATION.md
Local application http://localhost:5173
Local API health check http://localhost:3001/api/health

The live application is deployed on Vercel. The screenshots above show the supplied light and dark homepage views.

Features

Capability Description
Browser-side encryption The client encrypts content with AES-256-GCM before calling the API. The API persists ciphertext, salt, IV, and non-secret delivery metadata only.
Fragment-keyed links The decryption key lives after # in the share URL. Browsers do not send URL fragments in HTTP requests, so the server never receives the key.
Passphrase gate A sender can add an extra passphrase-based key derivation layer before sharing.
Burn after reading A note can be consumed exactly once; a successful non-owner read makes further reads unavailable.
Expiry and dead switches Notes can expire at a set time or disappear after an inactivity window.
Remote withdrawal The owner capability lets a sender delete a still-active note and its encrypted file blob.
Private encrypted-file delivery Files are encrypted in the browser. The Storage bucket is non-public; only a successful consume receives a 60-second, one-use API lease for ciphertext bytes.
Verified delivery receipts A receipt is recorded only when a browser successfully decrypts a random proof authenticated inside a version-two envelope. The server stores only the proof hash, never the raw proof or plaintext.
Encrypted recipient replies A sender may opt in to short voluntary recipient replies. The raw reply capability is inside the authenticated envelope; the browser encrypts each reply under a dedicated AES-GCM AAD domain, while the API stores only opaque ciphertext and a hash-only capability verifier. Owner capability is required to retrieve replies. Replies are unavailable for burn-after-read notes and do not authenticate a human identity.
Guardian Wipe A sender can create 2-of-3 through 5-of-5 trustee cards. A quorum may withdraw the server copy, but a single card—or every card—cannot decrypt the note or reveal its key.
Realtime collaboration drafts Temporary draft rooms use Supabase Realtime and are sealed or automatically purged after inactivity.
GitHub sign-in GitHub OAuth is handled by Supabase Auth; GitHub credentials stay in Supabase provider configuration, never in the browser bundle or API source.
Private account profile Authenticated users see provider identity, avatar, username, email, and an optional ≤160-character bio saved through owner-only Supabase RLS. No secret content or key material is stored there.
Browser-local vault The dashboard keeps links created in the current browser available for copying, receipt checks, and withdrawal without becoming a server-side plaintext archive.
Private vault contacts Each authenticated user can save/remove private GitHub username shortcuts through owner-only RLS. Contacts are not a directory, share recipient, or decryption-permission system.
Accessibility safeguards Axe-backed public-route checks, keyboard command-palette behavior, a skip link, visible focus treatment, and reduced-motion-aware interaction provide measurable accessibility evidence.
Production hardening Static CSP and companion security headers, request IDs, safe timing telemetry, a JavaScript bundle budget, pull-request CI, and a scheduled public smoke check protect release quality.
QR-assisted delivery The sealed-delivery card renders the full private link as an accessible QR code for intentional cross-device transfer.
Seal fingerprints Human-friendly word and glyph fingerprints can be compared with a recipient out of band before opening a sensitive note.

Security model

Locknote is designed around one boundary: the server can store an encrypted envelope, but it must not receive the decryption key.

Browser
  ├─ generates encryption material
  ├─ encrypts note or file locally
  ├─ sends ciphertext + delivery metadata ──────────┐
  └─ shares key only in URL fragment (#...)         │
                                                    ▼
                                            Locknote API / Supabase
                                            stores ciphertext only

The encrypted envelope includes ciphertext, a public 32-byte salt, IV, fixed KDF configuration, and delivery metadata. New version-two envelopes also carry a random delivery proof inside authenticated ciphertext; only its SHA-256 verifier is stored. When the sender enables encrypted replies, a separate random reply capability also stays inside the envelope while the service retains only its SHA-256 verifier. The service-role key is used only by server-side API functions to write and clean up encrypted records, private storage objects, opaque replies, and audit events. It must never be exposed through a VITE_ variable or committed to source control.

Guardian Wipe is revocation, not recovery. The browser splits a separate random wipe capability, not the encryption key. Guardian shares are checksum-protected and paste-bound; the service accepts only the reconstructed capability verifier. Guardians cannot open, decrypt, or recover the note.

Locknote improves private delivery; it does not protect a compromised sender or recipient device, an exposed share URL, or availability failures of the hosting provider. Use a trusted channel to send links and compare the note fingerprint out of band when assurance matters.

Known limitations and roadmap

Lock Note cannot erase plaintext a recipient has already copied, downloaded, photographed, or screen-captured. A verified delivery receipt proves that a browser with the encrypted proof successfully opened the envelope; it does not prove human comprehension. An encrypted reply is voluntary and does not authenticate a recipient identity; anyone holding the full link may be able to send or read one. Guardian Wipe revokes future server delivery but cannot retract a recipient copy. Collaboration rooms remain a temporary pre-seal workspace, not end-to-end encrypted co-editing. Planned work is limited to a staging-only load report, an optional independent security review, and user-recorded accessibility/demo evidence—rather than adding server-side access to plaintext or keys.

Collaboration privacy boundary

Realtime collaboration is a pre-seal drafting feature, not an end-to-end encrypted co-editing protocol. Draft content is synchronized through Supabase before the owner seals it into an encrypted Locknote envelope. Treat a collaboration room as a temporary workspace and do not enter material that must remain zero-knowledge until it has been sealed and shared as a note.

Architecture

Layer Technology Responsibility
Client React 19, Vite, TypeScript, Tailwind, Motion Encrypt/decrypt content, render the editor, manage share links, and use Supabase Auth/Realtime.
API Express 5, Zod, Helmet, rate limits Enforces fixed KDF policy, issues private one-use encrypted-file leases, validates proof/reply/Guardian verifiers, manages lifecycle operations, and emits privacy-safe timing/correlation metadata.
Persistence Supabase Postgres, private Storage, Realtime, Auth Stores ciphertext, hash-only capability verifiers, private encrypted file blobs, opaque encrypted reply envelopes, temporary collaboration drafts, and owner-only profile/contact metadata. It never stores note keys, raw proofs/capabilities, guardian shares, or plaintext.
Hosting Vercel Builds the Vite SPA, serves Express API functions under /api, and calls the protected daily maintenance function.
locknote/
├── api/                         # Vercel function entrypoints
│   ├── index.ts                 # /api
│   ├── [...path].ts             # /api/*
│   └── maintenance/purge.ts     # protected daily reconciliation
├── client/                      # React + Vite application
├── server/                      # Express API and storage abstractions
├── docs/
│   ├── assets/                  # README screenshots
│   ├── EVALUATION.md            # rubric-aligned evaluator evidence
│   ├── DEMO.md                  # three-to-five-minute walkthrough
│   ├── ENVIRONMENT.md           # local, Vercel, OAuth, and submission setup
│   └── sql/                     # Supabase bootstrap and RLS hardening migrations
├── vercel.json                  # Vite output, SPA routing, headers, cron
├── .env.example                 # safe local configuration template
└── .env.submission.template     # copyable private-submission template

Submission readiness

The repository is ready for code review and a live evaluation. Before submitting, replace the optional video placeholder above, confirm the live link opens, confirm the Quality gate workflow is green, and follow the submission checklist for private environment values.

Submission item Repository location
Rubric-by-rubric explanation docs/EVALUATION.md
Three-to-five-minute demo script docs/DEMO.md
Architecture and trust boundary docs/ARCHITECTURE.md and docs/SECURITY.md
API, changelog, and test evidence docs/API.md, CHANGELOG.md, and docs/TESTING.md
Safe environment templates .env.example and .env.submission.template
Live deployment https://lock-note-sigma.vercel.app/

Local setup

Requirements

Install Node.js 20 or newer, npm, and create a Supabase project. A GitHub OAuth application is only required if you want GitHub sign-in.

node --version
npm --version

1. Install dependencies

git clone https://github.com/Simondavid07/Lock_NOTE.git
cd Lock_NOTE
npm install

2. Create local environment values

cp .env.example .env

On Windows PowerShell:

Copy-Item .env.example .env

Fill the following values in .env:

SUPABASE_URL=https://YOUR_PROJECT_REF.supabase.co
SUPABASE_SERVICE_ROLE_KEY=your_server_only_service_role_key
VITE_SUPABASE_URL=https://YOUR_PROJECT_REF.supabase.co
VITE_SUPABASE_ANON_KEY=your_browser_safe_publishable_or_anon_key
CORS_ORIGINS=http://localhost:5173
PORT=3001

The SUPABASE_SERVICE_ROLE_KEY is server-only. Do not put it in a VITE_ variable and do not commit .env.

3. Bootstrap Supabase

For a new project, open Supabase Dashboard → SQL Editor, paste the complete contents of docs/sql/001_init.sql, and run it once. For an existing Locknote project, apply the migrations in numerical order through docs/sql/007_encrypted_recipient_replies.sql. These migrations are idempotent and create or harden:

  • public.pastes for encrypted note envelopes;
  • public.drafts for short-lived collaboration rooms, with database access restricted to the server-side API while Realtime Broadcast and Presence handle ephemeral collaboration;
  • public.events for privacy-safe lifecycle audit events;
  • public.paste_replies for bounded opaque encrypted recipient-reply envelopes, accessible only through server-side service-role operations and removed when their parent note is deleted;
  • the private secrets bucket for encrypted file blobs, accessed only through a short-lived server-issued lease; and
  • recurring database cleanup for expired notes and old drafts.

The secrets bucket is private by design. Even though objects are ciphertext, the recipient must first complete the envelope lifecycle to receive a 60-second one-use API lease; a Storage path is never included in public metadata or consume responses.

4. Start the application

npm run dev

This starts the Vite application at http://localhost:5173 and the Express API at http://localhost:3001. Vite forwards local /api requests to the Express server automatically.

GitHub OAuth with Supabase

Locknote uses Supabase Auth for GitHub OAuth. This is safer and simpler than exchanging GitHub codes in the application API.

  1. In GitHub, create an OAuth App at GitHub Developer Settings.

  2. In Supabase Dashboard → Authentication → Providers → GitHub, copy the supplied callback URL. It has this form:

    https://YOUR_PROJECT_REF.supabase.co/auth/v1/callback
    
  3. Set that value as the GitHub OAuth App Authorization callback URL.

  4. Enter the GitHub Client ID and Client Secret in the Supabase GitHub provider settings, enable the provider, and save.

  5. In Supabase Dashboard → Authentication → URL Configuration, set the production Site URL and allow these redirects:

    http://localhost:5173/auth/callback
    https://lock-note-sigma.vercel.app/auth/callback
    

The app asks Supabase to redirect to /auth/callback, exchanges the PKCE session code in the browser, and persists the resulting Supabase session. GitHub credentials do not belong in .env, VITE_ variables, or Vercel environment variables. Follow the official Supabase GitHub provider and redirect-URL guidance when configuring the provider. 1 2

Deploy to Vercel

Locknote is configured to deploy as one Vercel project:

  • client/dist is the static Vite output;
  • /api and /api/* are Express-backed Vercel functions;
  • SPA deep links resolve to index.html;
  • API responses receive no-store and MIME-sniffing protections; and
  • /api/maintenance/purge is a protected daily reconciliation job.

1. Import the repository

In Vercel, import the repository and keep the repository root as the project root. The checked-in vercel.json supplies the build command, output directory, SPA rewrite, headers, and cron schedule.

2. Add Vercel environment variables

Add these values for Production and Preview as appropriate:

Variable Required Exposure Value
SUPABASE_URL Yes Server only Supabase project URL.
SUPABASE_SERVICE_ROLE_KEY Yes Server only Service-role key. Never expose to the browser.
VITE_SUPABASE_URL Yes Browser build Same project URL.
VITE_SUPABASE_ANON_KEY Yes Browser build Supabase publishable/anon key.
CRON_SECRET Yes Server only Random string of at least 16 characters for maintenance authorization.
CORS_ORIGINS Optional Server only Only needed for a separately hosted frontend; same-project /api calls are same-origin.
VITE_API_BASE Optional Browser build Leave empty for the same Vercel project; set only for a separate API host.

Vite exposes only variables prefixed with VITE_ to the browser bundle. Treat every VITE_ value as public. The Vercel API runtime rejects missing Supabase server credentials instead of silently falling back to ephemeral in-memory storage.

3. Deploy and verify

Deploy from the Vercel dashboard or with the Vercel CLI. Once the deployment URL is available, run the live smoke test against it:

API_URL=https://lock-note-sigma.vercel.app npm run test:live

Vercel triggers the maintenance endpoint at 03:17 UTC daily. The endpoint checks CRON_SECRET, then performs an idempotent cleanup pass for expired records, stale drafts, and orphaned encrypted file blobs. Vercel cron requests use a protected Authorization header when CRON_SECRET is configured. 3

Vercel deploys Express applications as functions and supports Vite static builds; its SPA rewrite pattern is used here so direct links such as /paste/:id and /auth/callback work after a refresh. 4 5

Verify a setup

Run these commands before considering a deployment ready:

# Validates server, client, and Vercel function TypeScript entrypoints
npm run typecheck

# Builds the Express server and Vite client
npm run build

# Runs unit and integration coverage
npm run test

# Runs the API lifecycle smoke test against local API or API_URL
npm run test:live

The smoke test checks the health endpoint, encrypted-note creation, safe metadata responses, owner preview, burn-after-read behavior, delivery receipts, draft sealing, and remote withdrawal. Before releasing, confirm that GET /api/health reports ok: true and store: "supabase"; a local memory store or an unhealthy response is not production-ready.

Available scripts

Command Purpose
npm run dev Starts Vite and the Express API together.
npm run dev:client Starts only Vite on port 5173.
npm run dev:server Starts only Express on port 3001.
npm run typecheck Type-checks server, client, and api/ Vercel functions.
npm run build Builds server and client production artifacts.
npm run test Runs server and client test suites.
npm run test:live Runs the lifecycle smoke test against API_URL or localhost:3001.
npm run test:e2e Runs the optional end-to-end workspace suite.
npm run demo Runs the server demo workflow.

API and operational notes

The API reference lives in docs/API.md. For operations, use GET /api/health to check that the deployed function can reach Supabase. A healthy production response should report store: "supabase"; do not treat the local in-memory development fallback as a deployable persistence layer.

Before sharing a production URL, test these user journeys manually:

  1. Seal and open a text note from a second browser session.
  2. Confirm a burn-on-read note returns unavailable after the first non-owner open.
  3. Upload and retrieve an encrypted file note.
  4. Sign in with GitHub and return to /dashboard.
  5. Create and seal a collaboration draft.
  6. Run the live smoke test against the production URL.

Further documentation

Document Purpose
Documentation index Quick map of every evaluator and implementation document.
Evaluation guide Rubric-aligned evidence for problem fit, innovation, architecture, UX, reliability, and documentation.
Demo guide A concise evaluator walkthrough and troubleshooting sequence.
Environment guide Safe local, Vercel, OAuth, and submission configuration instructions.
Submission checklist Final reviewer, deployment, and secret-safety checks before handoff.
Feature guide Visual product tour of GitHub profile, vault, QR delivery, fingerprints, and lifecycle controls.
Architecture guide Service boundaries, data flow, and component overview.
Security and threat model Cryptographic protocol details and residual risks.
API reference API operations, payloads, and lifecycle behavior.
Testing guide Test coverage and verification guidance.
Supabase bootstrap migration Database, Storage, Realtime, RLS, and cleanup setup for new projects.
Supabase RLS hardening migration Removes legacy anonymous direct access to collaboration drafts.

License

This project is licensed under the MIT License.

References

About

Zero-knowledge secret sharing with browser-side AES-256-GCM encryption, verified delivery receipts, private one-use file delivery, burn/expiry controls, and Guardian Wipe threshold revocation. google drive link = https://drive.google.com/file/d/1sHMRiAYQcckZ7U8eix1QL32SBXohKMQM/view

Topics

Resources

Security policy

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages