Skip to content

ciscoAnass/GoFile

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

11 Commits
 
 
 
 
 
 
 
 
 
 

Repository files navigation

GoFile — Encrypted File Sharing (Go + Vanilla Web)

GoFile is a small self-hosted file sharing app that performs client-side encryption in the browser before upload.
The server stores only encrypted bytes plus minimal metadata in SQLite. Recipients download the encrypted payload and decrypt locally using a secret code shared out-of-band.

Key Features

  • Client-side encryption (AES-GCM) before any data leaves the device
  • Secret code wrapping: the per-upload encryption key is encrypted with a key derived from the secret code
  • Share by link: recipients open a URL and provide the secret code to decrypt
  • Expiry and download limits
  • Single or multi-file uploads
    • Single file uploads are stored as-is (encrypted)
    • Multiple files / folders are zipped in the browser (JSZip), then encrypted and uploaded as one archive
  • Server-side enforcement
    • Rejects expired, revoked, or download-limit-exceeded shares
    • Atomic download counter increment to avoid race issues
  • Large uploads
    • Total upload limit is 10 GiB (server-enforced)

How It Works

High-level Flow

  1. Upload page (/)

    • You select one or more files (or a folder).
    • The browser:
      • Creates a ZIP archive if multiple files/folders were selected.
      • Generates a random 32-byte encryption key.
      • Encrypts the file (or ZIP) using AES-GCM.
      • Generates a secret code (human-readable).
      • Derives a wrapping key from the secret code using PBKDF2 (SHA-256, 100,000 iterations).
      • Encrypts (wraps) the random encryption key with the wrapping key (AES-GCM).
    • The browser uploads:
      • The encrypted file bytes
      • The encrypted key (Base64)
      • File name, expiry, and download limit
  2. Server

    • Stores the encrypted blob on disk in ./data/<id>.bin
    • Stores metadata in ./shares.db (SQLite)
  3. Download page (/share.html?id=<id>)

    • The browser fetches metadata (/api/meta?id=...).
    • User enters the secret code.
    • The browser derives the wrapping key, decrypts the stored encryption key, downloads the encrypted file, and decrypts locally.

Security Model

  • The server never sees the plaintext content of uploaded files.
  • The server does receive:
    • Encrypted file bytes
    • Encrypted encryption key (wrapped key)
    • File name and policy metadata (expiry, max downloads)
  • The secret code is shown only once after upload; if lost, the content cannot be recovered.

Important: This app is designed for privacy-by-design file transport. It is not a substitute for a full access-control system, auditing, or enterprise key management.

Limits

  • Maximum upload size (server-enforced): 10 GiB
  • Multi-part parsing includes an additional overhead cushion of 32 MiB
  • Download limits:
    • maxDownloads = 0 means unlimited
    • Otherwise enforced atomically on each download request

Project Structure

.
├── server/
│   └── main.go
└── web/
    ├── index.html
    ├── share.html
    └── assets/
        ├── styles.css
        ├── upload.js
        ├── share.js
        └── images/

Requirements

  • Go (recent version recommended)
  • No separate database installation required (SQLite file is created locally)
  • A modern browser with WebCrypto support (Chrome, Edge, Firefox, Safari)

Run Locally

From the repository root:

cd server
go run .

Then open:

  • Upload page: http://localhost:8080/
  • Download page: http://localhost:8080/share.html

On first run, the server creates:

  • ./shares.db (SQLite database)
  • ./data/ (encrypted blob storage)

Usage

Upload

  1. Open http://localhost:8080/
  2. Select files or drag and drop (folders supported on compatible browsers)
  3. Choose:
    • Expires in
    • Max downloads (0 = unlimited)
  4. Click Encrypt and upload
  5. Save:
    • The share link
    • The secret code
  6. Send the link and the secret code via different channels.

Download

  1. Open the share link (example): http://localhost:8080/share.html?id=<id>
  2. Enter the secret code (format auto-applied)
  3. Click Decrypt and download
  4. If the download is a ZIP, extract it to get all files.

Server API

POST /api/create

Creates a share and uploads encrypted bytes.

  • Content-Type: multipart/form-data
  • Fields:
    • file (binary) — encrypted data
    • encryptedKeyB64 (string) — Base64 of AES-GCM wrapped encryption key
    • fileName (string)
    • expiresInSeconds (string/int)
    • maxDownloads (string/int, optional; defaults to 0)

Response (JSON):

{
  "id": "generated-id",
  "shareUrl": "/share.html?id=generated-id",
  "expiresAt": "2025-01-01T12:00:00Z"
}

GET /api/meta?id=<id>

Returns share metadata used by the download page.

Response (JSON):

{
  "id": "generated-id",
  "encryptedKeyB64": "base64...",
  "fileName": "archive.zip",
  "expiresAt": "2025-01-01T12:00:00Z",
  "maxDownloads": 0,
  "downloadsUsed": 0,
  "revoked": false,
  "createdAt": "2025-01-01T10:00:00Z"
}

Errors:

  • 404 Share not found
  • 403 Expired, revoked, or download limit exceeded

GET /api/download?id=<id>

Downloads encrypted bytes and increments the download counter (atomically).

  • Response: application/octet-stream
  • Content-Disposition is set to: <fileName>.encrypted

Errors:

  • 404 Share not found / file not found
  • 403 Expired, revoked, or download limit exceeded

Configuration Notes

The following values are currently constants in code:

  • Server listen address: :8080
  • Data directory: ./data
  • SQLite file: ./shares.db
  • Max upload size: 10 GiB
  • Multipart overhead cushion: 32 MiB
  • PBKDF2 parameters (client-side):
    • Salt: gofile-salt-v1
    • Iterations: 100000
    • Hash: SHA-256
  • Encryption algorithm: AES-GCM (12-byte IV)

If you intend to change PBKDF2 parameters, keep upload.js and share.js in sync, or old shares will not decrypt.

Production Considerations

If you deploy this publicly, consider:

  • Running behind a reverse proxy (Nginx/Caddy) with HTTPS
  • Setting timeouts and limits at the proxy level (upload size, request timeouts)
  • Access controls if you do not want a public upload endpoint
  • Monitoring disk usage and scheduling cleanup (current cleanup runs on each create request)
  • Backups of shares.db if you need metadata history (encrypted blobs are stored in ./data)

Troubleshooting

  • Upload fails with “File size exceeds 10GB limit”
    • The server enforces a strict 10 GiB limit. Reduce total selection size.
  • Download fails with “Invalid secret code.”
    • The secret code must match exactly; ensure you copied it correctly.
  • Share says expired
    • The expiration is enforced on metadata and download endpoints.
  • Multiple files download
    • You will receive a single ZIP archive; extract it after download.

About

An encrypted file sharing app where files are encrypted and decrypted in the browser, with expiring links and optional download limits, built with Go and vanilla web technologies.

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors