Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

stophecom/scrt-link-v2

Open more actions menu

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1,180 Commits
1,180 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

scrt-link-v2

scrt.link is a secure secret-sharing platform. Secrets are encrypted on the client before being sent to the server — the server never sees the plaintext. Once a secret has been viewed (or expires), it is permanently deleted.

Version 2 — built with SvelteKit and TypeScript.

Live: scrt.link

Developing

# 1. Install dependencies
pnpm install

# 2. Start DB (via Docker)
pnpm run db:start

# 3. Start sveltekit
pnpm run dev

# Run tests (unit and e2e)
pnpm test

Database

Using Drizzle with Postgres. Runs in Docker locally.

# You will need to set POSTGRES_URL in your production environment
# Reminder to myself: Using 5433 as port to not have conflict with local Postgres: https://stackoverflow.com/a/76448218

pnpm run db:start  # Start the docker container
pnpm run db:push # Update your database schema

# Local DB with Docker
docker compose up

Building

To create a production version of your app:

pnpm run build

Cron

We use Vercel Cron to cleanup secrets and files. See src/routes/api/v1/cron/+server.ts for more info.

You can trigger the cron job locally with:

curl --request POST \
     --url 'http://localhost:5173/api/v1/cron' \
     --header 'Authorization: Bearer CRON_SECRET'

UI / Components

https://www.shadcn-svelte.com/

# Install component (e.g. form)
pnpm dlx shadcn-svelte@latest add form

Translations / i18n

Translations are done with Paraglide.js by Inlang

# See project.inlang/settings.json for configurations
# Edit your messages in messages/en.json
# Consider installing the Sherlock IDE Extension
pnpm machine-translate # Machine translate missing keys

Usage

import { m } from '$lib/paraglide/messages.js';

// Sherlock IDE Extensions helps managing strings
const someString = m.elegant_muddy_wren_value();

Authentication

Implementation based on Lucia

The following login methods are available:

  • Email & Password (with email verification & password reset)
  • OAuth with Google

Google OAuth Client

Redirect URI: /login/google/callback

Subscriptions

We use Stripe as payment provider.

# Stripe CLI
# Test webhooks
stripe login
stripe listen --forward-to https://localhost:5173/api/v1/webhooks

# Trigger event
stripe trigger payment_intent.succeeded

Transactional Emails

📦 Project
├── 📂 src
│ └── 📂 lib
│   └── 📂 emails # Email templates
│
├── 📂 routes
│ └── 📂 admin
│   └── 📂 email-previews # Preview emails (Only works on localhost )
│
└── 📜 vite.config.ts # Tailwind setup

Workflows / E2E Testing

In order to ship with confidence we run a set of tests during and after the deployment. See playwright-tests-published.yml for more info.

Bypass Vercel Environment Protection

By default Vercel preview builds are protected and therefore can't be accessed by e2e-tests. Solution:

API

Since all secrets need to be encrypted on the client, the API relies on proper client-side handling. Therefore, API validation is not very strict.

Authentication

You can get an API key (bearer token) on the account page. (With proper access rights - see plans.)

Endpoints

/api/v1/secrets

Used to create secrets programmatically. To interact with the API, use the client-module. (See below)

# example.http
# IMPORTANT. The following is just for documentation purposes. Use the client-module to interact with the API.

# Post Secret
POST http://scrt.link/api/v1/secrets HTTP/1.1
Content-Type: application/json
Authorization: Bearer {{apiAccessToken}}

{
  "secretIdHash": "480bda04dbf90e580fe1124ff050ad1481509478521dc12242173294d9fec4be",
  "publicKey": "-----BEGIN PUBLIC KEY-----\nMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEbR5G6VDGfn8kPSE7y8MHY9PaWdgej1zz8nv6mN202pgOzuOzh221LoSFRprLhPqn9ykO+ZmvEMYVZa6+Wfk5GhEZpHl4QtJOGxH8rLhKqbLTJiBsLyXK0xm1u2N/UO1X\n-----END PUBLIC KEY-----",
  "meta": "XYZ", # Encrypted
  "content": "XYZ", # Encrypted
  "publicNote": "Lorem ipsum", # This is saved as plain text.
  "password": "my-secret-password", # Optional. Can be omitted.
  "expiresIn": 3600000 # Time in ms.
}

Client Module

Usage in Node.js / Browser:

<script type="module">
	import { scrtLink } from 'https://scrt.link/api/v1/client-module';

	// Instantiate client with API key.
	const client = scrtLink('ak_NcOWw69xw7XDjMK6QSYrw4LDlMOKYMK2F8Oqw4hoeMKiwrk5FcOLY1pqwqscdcOQ');

	// Basic usage
	client.createSecret('Some confidential information…').then(console.log);

	// With options
	client
		.createSecret('https://example.com', {
			secretType: 'redirect' // text | redirect | neogram
			password: 'foobar123'
			expiresIn: 86400000,
			publicNote: 'Bitcoin wallet address',
			host: 'br3f.com', // For white-label / business
		})
		.then(console.log);
</script>

Example response:

{
	"secretLink": "https://scrt.link/s#gOOei~kEkcYAAX-YJQnGooSXdSJg8MXkzk~2",
	"receiptId": "D0waygL3",
	"expiresIn": 86400000,
	"expiresAt": "2025-04-24T16:15:52.172Z"
}

Build npm client module

More info in packages/client.

# Build package
pnpm --filter @scrt-link/client build

# Publish package
cd packages/client
npm login
npm version patch
npm publish --access public

CLI

Install and use the scrtlink CLI to create encrypted secrets from the command line.

# Install globally
npm install -g @scrt-link/cli

Usage

# Set your API key once (or pass --api-key per command)
export SCRT_LINK_API_KEY=ak_...

# Basic — prints the secret link to stdout
scrtlink "super-secret-password"

# With options
scrtlink "https://example.com" \
  --type redirect \
  --expires 1h \
  --views 5 \
  --password "unlock123"

# White-label instance
scrtlink "my secret" --host br3f.com

Options:

Flag Description Default
--type text | redirect | neogram text
--expires 1h | 1d | 1w | 1m 1w
--views View limit 1–1000 1
--note Public note shown before reveal
--password Password-protect the secret
--host Override API host (white-label) scrt.link
--api-key API key (overrides env var)

The command prints the secret link to stdout, making it pipeable:

scrtlink "my secret" | pbcopy
echo "my secret" | xargs scrtlink

Build & publish

# Build
pnpm --filter @scrt-link/cli build

# Publish
cd packages/cli
npm login
npm version patch
npm publish --access public

Build API provided client module

# The esm module is built during deployment as part of postbuild and saved in the /static folder.
# If you need to make adjustments, see $lib/client/client-module.ts
# Build the module locally with:
esbuild src/lib/client/client-module.ts --bundle --format=esm --minify --outfile=static/client-module.js

# For vercel:
esbuild src/lib/client/client-module.ts --bundle --format=esm --minify --outfile=.vercel/output/static/client-module.js

# Shortcut
pnpm build-client-module

User image handling

We store images (logo, app icons) for white-label sites on S3 and serve optimized images via imagx.

# Imgix image CDN
PUBLIC_IMGIX_CDN_URL="scrt-link.imgix.net"

White-label with HTTPS (local)

To test the white-label multi-tenant setup locally you need HTTPS with a custom domain.

  1. Install mkcert and set up a local CA:
brew install mkcert
mkcert -install
  1. Generate certificates for your white-label domain and localhost:
mkcert wl.scrt.link localhost 127.0.0.1 ::1

This creates wl.scrt.link.pem and wl.scrt.link-key.pem in the current directory.

  1. Add the domain to /etc/hosts:
127.0.0.1 wl.scrt.link
  1. The vite.config.ts automatically picks up the certificates if they exist. No config changes needed — HTTPS is enabled conditionally when .pem files are present.

Note: The .pem files are gitignored and must be generated per machine.

Error Handling

We use SvelteKit recommendation: https://svelte.dev/docs/kit/errors Expected errors are returned with error(404, 'Some message') and might be shown to users. For internal errors (mostly unexpected) we use throw new Error().

Stack

  • SvelteKit
  • Tailwind CSS
  • PostgreSQL (Database)
  • Drizzle (ORM)
  • Inlang/Paraglide (i18n)
  • Resend (Email)

Infrastructure

License

MIT (Code)

CC BY-NC-ND (Creatives)

About

Scrt.link lets you share sensitive information online: End-to-end encrypted. Ephemeral. Open source.

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Morty Proxy This is a proxified and sanitized view of the page, visit original site.