{"id":15155191,"url":"https://github.com/johanns/ref-secure-share","last_synced_at":"2026-02-05T18:31:00.440Z","repository":{"id":254800626,"uuid":"847568799","full_name":"johanns/ref-secure-share","owner":"johanns","description":"SecureShare is a tutorial and reference implementation of a one-time-use message sharing web-app, developed using Next.JS 14, TypeScript, Prisma, and styled with Tailwind CSS","archived":false,"fork":false,"pushed_at":"2024-10-04T04:55:46.000Z","size":533,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2024-10-29T23:07:53.232Z","etag":null,"topics":["cryptography","next","tailwindcss","tutorial","typescript","webcrypto"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/johanns.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2024-08-26T05:50:19.000Z","updated_at":"2024-10-04T04:55:49.000Z","dependencies_parsed_at":"2024-08-26T07:34:12.893Z","dependency_job_id":"8a6c371c-27d2-4501-9aa3-169ed45cf9e5","html_url":"https://github.com/johanns/ref-secure-share","commit_stats":{"total_commits":15,"total_committers":2,"mean_commits":7.5,"dds":0.06666666666666665,"last_synced_commit":"fecb7dd1cc900953bca07ac5715a018a7153c678"},"previous_names":["johanns/celox.js"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/johanns%2Fref-secure-share","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/johanns%2Fref-secure-share/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/johanns%2Fref-secure-share/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/johanns%2Fref-secure-share/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/johanns","download_url":"https://codeload.github.com/johanns/ref-secure-share/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":223472707,"owners_count":17150744,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["cryptography","next","tailwindcss","tutorial","typescript","webcrypto"],"created_at":"2024-09-26T18:02:49.005Z","updated_at":"2026-02-05T18:31:00.434Z","avatar_url":"https://github.com/johanns.png","language":"TypeScript","readme":"## Secure Share web-app\n\n\u003e [!WARNING]\n\u003e This project is part of an in-person tutorial series and serves as a reference implementation for educational purposes. The goal is to demonstrate how to build a simple product with real-world utility beyond academic exercises. It is not intended for production use.\n\nSecureShare is a tutorial and reference implementation of a one-time-use message sharing web-app, developed using Next.JS 14, TypeScript, Prisma, and styled with Tailwind CSS\n\n### Core functionality\n\n#### Client-Side Encryption:\nMessages are encrypted directly within the sender's browser before transmission. This ensures that the server only receives and stores the encrypted data, without ever accessing the encryption key.\n\n#### Unique URL Generation:\nAfter storing the encrypted message, the server generates a unique retrieval key and returns it to the sender. The sender then constructs a unique URL that includes this retrieval key and appends the encryption key in the URL's anchor (the portion after #). Since the anchor is not sent to the server during HTTP requests, the server remains unaware of the encryption key.\n\n#### Secure Message Retrieval and Decryption:\nRecipients use the unique URL to fetch the encrypted message from the server. The encryption key embedded in the URL's anchor allows them to decrypt the message locally in their browser.\n\n#### One-Time Access Enforcement:\nOnce the message has been viewed, it is automatically marked as read, and its content is overwritten on the server. This ensures that the message can only be accessed a single time, maintaining its one-time-use nature.\n\nSee [Sequence diagram](#sequence-diagram) below for a detailed overview of the process\n\n![Demo](/doc/screencast.gif)\n\n#### Technology Stack:\n\n    Framework: Next.js 14\n     Language: TypeScript\n          ORM: Prisma (for PostgreSQL)\n      Styling: Tailwind CSS\n\n### System requirements\n\n- Node.js (16.x or later) or Bun (1.1 or later)\n- PostgreSQL (13.x or later)\n\n### Recommended tools\n\n- Visual Studio Code\n- Postman\n- Chrome\n\n### Setup\n\n1. Clone the repository:\n\n```bash\ngit clone git@github.com:johanns/ref-secure-share.git\n```\n\n2. Install dependencies:\n\n```bash\nnpm install\n```\nor\n```bash\nbun install\n```\n\n3. Create a `.env` file in the project root and add the following environment variables:\n\n```bash\nDATABASE_URL=\"postgresql://\u003cusername\u003e:\u003cpassword\u003e@localhost:5432/\u003cdatabase\u003e\"\n```\n\nNOTE: Replace `\u003cusername\u003e`, `\u003cpassword\u003e`, and `\u003cdatabase\u003e` with your PostgreSQL credentials.\n\n4. Run the Prisma migration:\n\n```bash\nnpx prisma migrate dev\n```\nor\n```bash\nbun run prisma migrate dev\n```\n\n5. Run the development server:\n\n```bash\nnpm run dev\n```\nor\n```bash\nbun run dev\n```\n\n5. Open your browser and navigate to `http://localhost:3000`.\n\n### Project directory structure and core files\n\n```\nprisma\n├── migrations/ -- Database migration files\n└── schema.prisma -- Prisma schema definition\n\nsrc\n├── app\n│   ├── api\n│   │   └── message\n│   │       ├── route.ts -- Message creation endpoint (POST)\n│   │       └── [stub]\n│   │           └── route.ts -- Message retrieval endpoint (GET, DELETE)\n│   ├── layout.tsx -- Application layout\n│   ├── page.tsx -- Message creation page\n│   └── [stub]\n│       └── page.tsx -- Message retrieval page\n├── assets\n│   └── css\n│       └── globals.css\n├── lib\n│   ├── crypto.ts - Client-side encryption/decryption functions\n│   ├── modelValidationError.ts - Model validation error handler\n│   └── prisma.ts - Prisma client initialization\n└── models\n    └── message.ts - Message model\n```\n\n### Sequence diagram\n\n#### Compose (happy path)\n\n```mermaid\nsequenceDiagram\n    autonumber\n\n    Sender-\u003e\u003eServer: GET /\n    Server--\u003e\u003eSender: Render \u003cbr /\u003e /app/page.tsx\n\n    note over Sender,Server: On form submit\n    Sender-\u003e\u003eSender: Generate encryption key \u003cbr /\u003e /lib/crypto.ts\n    Sender-\u003e\u003eSender: Encrypt data \u003cbr /\u003e /lib/crypto.ts\n    Sender-\u003e\u003e+Server: Submit encrypted form data\n\n    Server\u003c\u003c--\u003e\u003eDatabase: Find unique retrieval stub \u003cbr /\u003e /models/message.ts\n    Server\u003c\u003c--\u003e\u003eDatabase: Store encrypted form data \u003cbr /\u003e /models/message.ts\n    Server--\u003e\u003e-Sender: Render JSON: {stub: stub}\n\n    Sender-\u003e\u003eSender: Construct retrieval URL \u003cbr /\u003e (stub + key)\n\n    note over Sender,Server: Show retrieval URL\n```\n\n#### Retrieve (happy path)\n\n```mermaid\nsequenceDiagram\n    autonumber\n\n    Recipient-\u003e\u003e+Server: GET /\u003cstub\u003e \u003cbr /\u003e /app/[stub]/page.tsx\n    Server--\u003e\u003e-Recipient: Render page\n\n    note over Recipient,Server: On page load \u003cbr /\u003e useEffect(...)\n\n    Recipient-\u003e\u003e+Server: GET /api/message/[stub] \u003cbr /\u003e /app/api/message/[stub]/route.ts\n    Server\u003c\u003c--\u003e\u003eDatabase: Find encrypted data \u003cbr /\u003e /models/message.ts\n    Server\u003c\u003c--\u003e\u003eDatabase: Mark message as read \u003cbr /\u003e /models/message.ts\n    Server--\u003e\u003e-Recipient: Render JSON: {data: encryptedData}\n\n    Recipient-\u003e\u003eRecipient: Extract key from URL \u003cbr /\u003e /lib/crypto.ts\n    Recipient-\u003e\u003eRecipient: Decrypt data \u003cbr /\u003e /lib/crypto.ts\n\n    note over Recipient,Server: Show decrypted data or already read notice\n```\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjohanns%2Fref-secure-share","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjohanns%2Fref-secure-share","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjohanns%2Fref-secure-share/lists"}