{"id":35103457,"url":"https://github.com/remimikalsen/sharepass","last_synced_at":"2026-02-15T18:06:09.124Z","repository":{"id":275906246,"uuid":"926975773","full_name":"remimikalsen/sharepass","owner":"remimikalsen","description":"CredShare.app is a simple and secure sharing service for passwords or other secrets.","archived":false,"fork":false,"pushed_at":"2026-01-02T09:21:44.000Z","size":274,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2026-01-08T08:36:46.326Z","etag":null,"topics":["credentials","password-safety","security","sharing"],"latest_commit_sha":null,"homepage":"https://credshare.app","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/remimikalsen.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":"SECURITY_REVIEW.md","support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-02-04T07:26:01.000Z","updated_at":"2026-01-02T09:20:21.000Z","dependencies_parsed_at":"2025-03-18T00:20:13.363Z","dependency_job_id":"885d6aca-04fa-4c88-9dc4-72050ddf60d3","html_url":"https://github.com/remimikalsen/sharepass","commit_stats":null,"previous_names":["remimikalsen/sharepass"],"tags_count":23,"template":false,"template_full_name":null,"purl":"pkg:github/remimikalsen/sharepass","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/remimikalsen%2Fsharepass","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/remimikalsen%2Fsharepass/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/remimikalsen%2Fsharepass/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/remimikalsen%2Fsharepass/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/remimikalsen","download_url":"https://codeload.github.com/remimikalsen/sharepass/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/remimikalsen%2Fsharepass/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29486068,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-15T15:33:17.885Z","status":"ssl_error","status_checked_at":"2026-02-15T15:32:53.698Z","response_time":118,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"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":["credentials","password-safety","security","sharing"],"created_at":"2025-12-27T17:34:03.589Z","updated_at":"2026-02-15T18:06:09.118Z","avatar_url":"https://github.com/remimikalsen.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"![Test Status](https://img.shields.io/github/actions/workflow/status/remimikalsen/sharepass/tests.yaml?label=tests)\n![Coverage Badge](https://raw.githubusercontent.com/remimikalsen/sharepass/refs/heads/main/tests/coverage-badge.svg)\n![Build Status](https://img.shields.io/github/actions/workflow/status/remimikalsen/sharepass/build.yaml)\n![License](https://img.shields.io/github/license/remimikalsen/sharepass)\n![Version](https://img.shields.io/github/tag/remimikalsen/sharepass)\n\n# CredShare\n\n**CredShare is a simple and secure sharing service for passwords or other secrets.**\n\nCredShare allows you to share sensitive information safely over the internet. Enter your secret and a key to encrypt it in your browser, and you’ll receive a secure, shareable link. Once the secret is unlocked or expires, it’s automatically deleted.\n\nCredShare maintains anonymity while limiting usage by hashing client IP addresses. You can customize quotas, renewal intervals, secret expiry, and more.\n\nCredShare is asynchronous by nature, allowing it to scale efficiently even on modest hardware. For additional scalability, you can deploy multiple CredShare containers behind a load balancer.\n\n\u003e **Note:** CredShare doesn’t encrypt network traffic on its own. For secure transmission, it is recommended to run it behind a reverse proxy (e.g., Nginx or Traefik) that terminates TLS. CredShare reads the `X-Forwarded-For` header to determine the originating client IP.\n\n## Table of Contents\n\n- [Features](#features)\n- [How it Works](#how-it-works)\n  - [Create the Secret](#create-the-secret)\n  - [Unlocking the Secret](#unlocking-the-secret)\n  - [Quota Management](#quota-management)\n  - [Secret Expiry and Purging](#secret-expiry-and-purging)\n- [Setup and Configuration](#setup-and-configuration)\n  - [Using a Pre-Built Image](#using-a-pre-built-image)\n  - [Building the Image Yourself](#building-the-image-yourself)\n    - [Clone the Repository](#clone-the-repository)\n    - [Using Docker Compose](#using-docker-compose)\n    - [Using Docker](#using-docker)\n- [Configuration Options](#configuration-options)\n- [Accessing the Web Interface](#accessing-the-web-interface)\n- [API Usage (CLI/curl)](#api-usage-clicurl)\n- [Developer Notes](#developer-notes)\n\n## Features\n\n- **Secure Secret Sharing:** Encrypt secrets in your browser before they are sent to the server.\n- **One-Time Access:** Secrets are deleted after being viewed or after a set expiry time.\n- **Usage Quotas:** Limits on uploads per IP address to prevent abuse.\n- **Configurable:** Adjustable settings for expiry, quota renewal, and purge intervals.\n\n## How it Works\n\n### Create the Secret\n\n1. The user enters the secret and the key for unlocking it.\n2. The browser encrypts the secret with the key, generates a unique download code, and stores the encrypted secret in a SQLite database.\n3. The user receives a download link that can be used to enter the unlock code.\n\n### Unlocking the Secret\n\n1. Users can unlock a secret using the provided download link.\n2. The server verifies the download code and prompts for the unlocking key.\n3. If the unlocking key matches, the secret is revealed.\n4. The user can choose to copy the secret to the clipboard or view it on screen.\n5. The encrypted secret is deleted from the server once unlocked.\n6. If the unlocking attempts exceed the limit, the encrypted secret is deleted.\n7. The download link is valid for a single use and also expires after a specified time.\n\n### Quota Management\n\n- The app tracks the number of uploads per IP address to enforce a time-based usage quota.\n- The quota resets periodically based on the configured interval.\n\n### Secret Expiry and Purging\n\n- Uploaded secrets have an expiry time after which they are deleted.\n- A scheduled task periodically purges expired secrets and cleans up the database.\n\n## Setup and Configuration\n\n### Using a Pre-Built Image\n\nIf you trust the pre-built images, fetch the latest image and run it:\n\n```sh\ndocker pull ghcr.io/remimikalsen/credshare:v1\n```\n\nConfigure it with the parameters indicated below, or use the `docker-compose.yml` example in the repository.\n\n### Building the Image Yourself\n\nIf you prefer to build from source for security reasons, follow these steps:\n\n#### Clone the Repository\n\n```sh\ngit clone https://github.com/remimikalsen/sharepass\n```\n\n#### Using Docker Compose\n\nModify the `docker-compose.yml` file so the build/image section looks like this:\n\n```yaml\nservices:\n  sharepass:\n    ...\n    container_name: sharepass\n    # image: ghcr.io/remimikalsen/credshare:v1\n    build:\n      context: .\n      dockerfile: Dockerfile.sharepass\n    ...\n```\n\nThen build and run the image:\n\n```sh\ncd sharepass\ndocker compose up -d\n```\n\n#### Using Docker\n\n```sh\ncd sharepass\ndocker build -t sharepass-image -f Dockerfile.sharepass .\ndocker run -d \\\n  --name sharepass \\\n  --restart unless-stopped \\\n  -p 8080:8080 \\\n  -e MAX_USES_QUOTA=5 \\\n  -e MAX_ATTEMPTS=5 \\\n  -e SECRET_EXPIRY_MINUTES=1440 \\\n  -e QUOTA_RENEWAL_MINUTES=60 \\\n  -e PURGE_INTERVAL_MINUTES=5 \\\n  -v /sharepass/database:/app/database \\\n  sharepass-image\n```\n\n## Configuration Options\n\nModify `--env` variables or your `docker-compose.yml` file to match your setup:\n\n- `HTTPS_ONLY`: Set to true to enable Strict-Transport-Security header (default: false)\n- `MAX_USES_QUOTA`: Maximum uploads allowed per IP address (default: 5).\n- `MAX_ATTEMPTS`: Maximum number of unlocking attempts (default: 5).\n- `SECRET_EXPIRY_MINUTES`: Time in minutes before a secret expires (default: 1440 minutes or 24 hours).\n- `QUOTA_RENEWAL_MINUTES`: Interval for resetting the usage quota (default: 60 minutes).\n- `PURGE_INTERVAL_MINUTES`: Interval for purging expired secrets (default: 5 minutes).\n- `ANALYTICS_SCRIPT`: Complete script tag needed for tracking (default: '').\n- `ANALYTICS_SCRIPT_CSP`: If the analytics script is located on a different domain, add the domain to the CSP header; e.g. https://plausible.yourdomain.com (default: '')\n\nEnsure that the database directory exists on your system to persist the database.\n\n## Accessing the Web Interface\n\nVisit [http://localhost:8080](http://localhost:8080).\n\n## API Usage (CLI/curl)\n\nSharepass can also be used as a CLI tool via its API endpoints. Secrets created via the web interface can be retrieved via curl, and vice versa.\n\n### Using the CLI Helper\n\nA Python helper script is provided for easy encryption:\n\n```sh\n# Encrypt a secret and generate a curl command\npython sharepass_cli.py \"my secret\" -k \"my-key\" -o curl\n\n# Or output just the encryption JSON for custom usage\npython sharepass_cli.py \"my secret\" -k \"my-key\"\n\n# Read secret from stdin\necho \"my secret\" | python sharepass_cli.py - -k \"my-key\"\n```\n\n### Creating a Secret via API\n\n**Unix/Linux/Mac (bash):**\n\n```sh\n# 1. Encrypt the secret using the helper script\nENCRYPTED=$(python sharepass_cli.py \"my secret\" -k \"my-key\")\n\n# 2. Create the secret via API (encrypted_secret must be a JSON string)\ncurl -X POST http://localhost:8080/api/lock \\\n  -H 'Content-Type: application/json' \\\n  -d \"{\\\"encrypted_secret\\\": \\\"$ENCRYPTED\\\"}\"\n\n# Response: {\"download_code\": \"abc123...\", \"url\": \"/unlock/abc123...\"}\n```\n\n**Windows PowerShell:**\n\n```powershell\n# 1. Encrypt the secret using the helper script\n$ENCRYPTED = python sharepass_cli.py \"my secret\" -k \"my-key\"\n\n# 2. Create the secret via API using Invoke-RestMethod\n$body = @{\n    encrypted_secret = $ENCRYPTED\n} | ConvertTo-Json\n\nInvoke-RestMethod -Uri http://localhost:8080/api/lock `\n  -Method Post `\n  -ContentType \"application/json\" `\n  -Body $body\n\n# Or using curl.exe explicitly (if available)\ncurl.exe -X POST http://localhost:8080/api/lock `\n  -H \"Content-Type: application/json\" `\n  -d \"{\\\"encrypted_secret\\\": \\\"$ENCRYPTED\\\"}\"\n```\n\n### Retrieving a Secret via API\n\n**Unix/Linux/Mac (bash):**\n\n```sh\n# Unlock and retrieve the secret\ncurl -X POST http://localhost:8080/api/unlock \\\n  -H 'Content-Type: application/json' \\\n  -d '{\"download_code\": \"abc123...\", \"key\": \"my-key\"}'\n\n# Response: {\"secret\": \"my secret\"}\n```\n\n**Windows PowerShell:**\n\n```powershell\n# Unlock and retrieve the secret using Invoke-RestMethod\n$body = @{\n    download_code = \"abc123...\"\n    key = \"my-key\"\n} | ConvertTo-Json\n\nInvoke-RestMethod -Uri http://localhost:8080/api/unlock `\n  -Method Post `\n  -ContentType \"application/json\" `\n  -Body $body\n\n# Or using curl.exe explicitly (if available)\ncurl.exe -X POST http://localhost:8080/api/unlock `\n  -H \"Content-Type: application/json\" `\n  -d '{\"download_code\": \"abc123...\", \"key\": \"my-key\"}'\n```\n\n### API Endpoints\n\n- `POST /api/lock` - Create a secret\n  - Request: `{\"encrypted_secret\": \"...\"}` (JSON string from encryption)\n  - Response: `{\"download_code\": \"...\", \"url\": \"/unlock/...\"}`\n\n- `POST /api/unlock` - Retrieve a secret\n  - Request: `{\"download_code\": \"...\", \"key\": \"...\"}`\n  - Response: `{\"secret\": \"...\"}` or error message\n\nThe encryption format matches the web interface: AES-GCM with PBKDF2 key derivation (100,000 iterations, SHA-256).\n\n## Developer Notes\n\n### Python dependencies\n\nSet up a Python virtual environment for local development to manage Python package versions correctly.\n\nThere are two sets of pinned dependencies:\n\n- `requirements.in` / `requirements.txt` — **production** dependencies (used in Docker).\n- `requirements-dev.in` / `requirements-dev.txt` — **dev/test** dependencies (pre-commit, pip-tools, pip-audit, pytest, etc.), constrained against the production pins.\n\n#### Initial setup\n\n```sh\npython -m venv venv\nsource venv/bin/activate   # On Windows: venv\\Scripts\\activate\npip install pip-tools\n\n# Compile both requirement files\npip-compile requirements.in\npip-compile requirements-dev.in\n\n# Install everything for local development\npip-sync requirements.txt requirements-dev.txt\n```\n\n#### Upgrading dependencies\n\n```sh\n# Upgrade production deps\npip-compile --upgrade requirements.in\n\n# Re-compile dev deps (picks up new production constraints)\npip-compile --upgrade requirements-dev.in\n\n# Audit for known vulnerabilities before installing\npip-audit -r requirements.txt\npip-audit -r requirements-dev.txt\n\n# Apply the upgrades\npip-sync requirements.txt requirements-dev.txt\n```\n\n#### Production vs. development\n\n- **Production (Docker):** Only `requirements.txt` is installed — the Dockerfile never sees dev dependencies.\n- **Local development:** Always sync both files so that `pre-commit`, test tools, and dev utilities stay installed:\n\n  ```sh\n  pip-sync requirements.txt requirements-dev.txt\n  ```\n\n\u003e **Security note:** Avoid using `pip install --upgrade \u003cpackage\u003e` directly, as it may pull in untested or incompatible versions. Instead, always use `pip-compile --upgrade` to resolve and pin all dependencies in a reproducible way. Then run `pip-audit` to check for known vulnerabilities before applying them with `pip-sync`. This ensures every upgrade is audited, recorded in version control, and tested before deployment.\n\n### Javascript dependencies\n\nNpm is used to manage packages and webpack to bundle a minimal hightlight package.\n\nTo upgrade npm packages (although, the latest versions are automatically installed on each docker build):\n\nSafe updates:\n\n```sh\nnpm update\n```\n\nUpdate including across major versjons (breaking):\n\n```\nnpm outdated \u0026\u0026 npx npm-check-updates -u \u0026\u0026 npm install\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fremimikalsen%2Fsharepass","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fremimikalsen%2Fsharepass","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fremimikalsen%2Fsharepass/lists"}