SealNotes

repository·main·Indexed 42 days ago

https://github.com/harshsbhat/sealnotes

An end-to-end encrypted, web-based notepad for secure, distraction-free note-taking without user accounts. It utilizes client-side AES-256 encryption and a zero-knowledge architecture to ensure privacy, with a deployment stack including Redis and serverless-redis-http.

Tokens
2.3K
Snippets
9
Records
12
Agent score
54%

What's inside SealNotes

  1. SealNotes Security Model

    main

    SealNotes implements an end-to-end encryption model to ensure privacy:

    • Client-Side Encryption: All text data is encrypted using AES-256 on the client side before storage. The server only ever sees and stores encrypted data.
    • Secure Hashing: Notepad names are securely hashed before being saved to the database to prevent identification.
    • Zero-Knowledge Architecture: The service does not store passwords and has no access to the encryption keys. Without the user's password, the notes are undecipherable.
    • Privacy: The platform does not track user activity or store metadata.
  2. How to use SealNotes

    main

    SealNotes is a web-based notepad that uses end-to-end encryption. You can use it without an account by following these steps:

    1. Create a Note: Visit https://sealnotes.com/ and enter a unique name for the note's URL.
    2. Set Encryption: Choose a strong password. This password is used for client-side AES-256 encryption; SealNotes does not store your password and cannot decrypt your notes without it.
    3. Write and Save: Enter your text in the editor and click "Save". The text is encrypted locally before being sent to the server.
    4. Accessing Notes: To retrieve a note, navigate to its unique URL and provide the correct password.
  3. Set up SealNotes locally

    main

    To run a local instance of SealNotes, follow these steps:

    1. Clone the repository.
    2. Install dependencies using pnpm.
    3. Initialize your environment variables by copying the example file.
    4. Start the local development environment.

    Prerequisites:

    • git
    • pnpm
    git clone https://github.com/harshsbhat/sealnotes.git
    cd sealnotes
    pnpm install
    cp .env.example .env
    pnpm local
  4. Deploy SealNotes with Docker Compose

    main

    You can deploy the SealNotes stack using the provided docker-compose.yaml. The setup includes a standard redis service and a serverless-redis-http service which acts as an HTTP bridge to Redis.

    By default, the services expose the following ports:

    • Redis: 6379
    • Serverless Redis HTTP: 8079 (mapped to container port 80)
    version: 'sealnotes'
    services:
      redis:
        image: redis
        restart: always
        ports:
          - '6379:6379'
    
      serverless-redis-http:
        ports:
          - '8079:80'
        image: hiett/serverless-redis-http:latest
        restart: always
        environment:
          SRH_MODE: env
          SRH_TOKEN: password
          SRH_CONNECTION_STRING: 'redis://redis:6379'
  5. Encrypt text using AES-256-CBC

    main

    The encrypt function secures a string using AES-256-CBC encryption. It derives a cryptographic key from a provided password using PBKDF2 with 100,000 iterations and a static salt.

    The function returns a single string in the format iv:encryptedData, where both the Initialization Vector (IV) and the encrypted payload are hex-encoded. If the input text is empty, it defaults to a single space (" ").

    import { encrypt } from "./path/to/vault";
    
    const password = "my-secure-password";
    const secretMessage = "Hello, SealNotes!";
    
    const encryptedString = encrypt(secretMessage, password);
    // Output format: "<hex-iv>:<hex-ciphertext>"
  6. Generate a SHA-256 hash

    main

    The sha256 function computes a SHA-256 hash of a given string and returns the result as a hex-encoded string. This is useful for creating unique identifiers or verifying data integrity.

    import { sha256 } from "./path/to/vault";
    
    const hash = sha256("some content");
    // Returns a 64-character hex string
  7. Use the Client component to render decrypted notes

    main

    The Client component is the primary client-side entrypoint for the SealNotes application. It is responsible for rendering the user interface for managing multiple notes, handling tab switching, editing content via a rich text editor, and performing secure save/refresh operations. It requires decrypted data and a hash to initialize the state and ensure data integrity during subsequent writes.

    To use this component, you must provide:

    • params: The URL slug/identifier for the specific note site.
    • decryptedData: A JSON string containing the decrypted array of notes.
    • hash: The initial hash used for password/security context.

    Note: The component manages its own internal state for 'dirty' tabs (unsaved changes) and will trigger a browser warning if the user attempts to leave the page with unsaved changes.

    import { Client } from "@/app/[...slug]/client";
    
    // Example usage in a parent component or page
    <Client 
      params="my-secure-site" 
      decryptedData='[{"title": "Note 1", "description": "Content"}]' 
      hash="initial-hash-value" 
    />
  8. Decrypt text using AES-256-CBC

    main

    The decrypt function reverses the encryption performed by encrypt. It expects an encrypted string in the format iv:encryptedData (hex-encoded components separated by a colon).

    Requirements:

    • The encryptedText must contain exactly one colon separating the IV and the ciphertext.
    • The password provided must be the same one used during encryption, as the key is derived via PBKDF2.

    Errors:

    • Throws if encryptedText is empty.
    • Throws if the format is not iv:ciphertext.
    • Throws if either the IV or the ciphertext part is missing.
    import { decrypt } from "./path/to/vault";
    
    const password = "my-secure-password";
    const encryptedString = "<hex-iv>:<hex-ciphertext>";
    
    try {
      const originalText = decrypt(encryptedString, password);
      console.log(originalText);
    } catch (error) {
      console.error("Decryption failed:", error.message);
    }
  9. Configure serverless-redis-http environment variables

    main

    The serverless-redis-http service uses the following environment variables for configuration:

    VariableDescription
    SRH_MODESet to env to use environment variables for configuration.
    SRH_TOKENThe authentication token required to access the HTTP interface.
    SRH_CONNECTION_STRINGThe connection URI for the Redis instance (e.g., redis://redis:6379).
    environment:
      SRH_MODE: env
      SRH_TOKEN: password
      SRH_CONNECTION_STRING: 'redis://redis:6379'
  10. Skip environment variable validation

    main

    If you need to bypass environment variable validation (for example, during a Docker build where variables might not be available yet), you can use the SKIP_ENV_VALIDATION environment variable. Setting this to any truthy value will allow the build or development process to proceed even if the required schema is not met.

    SKIP_ENV_VALIDATION=true npm run build
  11. Required environment variables for SealNotes

    main

    SealNotes requires specific environment variables for its server-side operations, particularly for Upstash Redis integration. If these are missing or invalid, the application will fail validation during build or development.

    Server-side Variables

    • NODE_ENV: The current environment. Must be one of development, test, or production. Defaults to development.
    • UPSTASH_REDIS_REST_URL: The REST URL for the Upstash Redis instance.
    • UPSTASH_REDIS_REST_TOKEN: The authentication token for the Upstash Redis instance.

    Validation Behavior

    • Empty Strings: Empty strings are treated as undefined. For example, setting UPSTASH_REDIS_REST_URL='' will trigger a validation error if the schema expects a string.
    # Example configuration
    NODE_ENV=production
    UPSTASH_REDIS_REST_URL=https://your-url.upstash.io
    UPSTASH_REDIS_REST_TOKEN=your-token