Skip to main content

Upload files/folders to Cloudflare R2 and get a shareable link

Project description

rink

PyPI version Python versions License: MIT

rink is a fast, terminal-first utility to upload files or directories directly to a Cloudflare R2 bucket and instantly get a shareable URL.

Cloudflare R2 objects are private by default, so rink provides two ways to share:

  • Presigned Links (Default): A secure, signed URL that automatically expires (up to 7 days). Does not require public bucket access.
  • Public Links: A permanent URL (https://<pub-domain>/<key>) using your bucket's public access domain.

Features

  • Direct Uploads: Single files, multiple files, folders, or piped input from standard input (stdin).
  • Flexible Folder Handling: Zip directories automatically into a single file, or upload them recursively in parallel.
  • Terminal Enhancements: Copy links directly to your clipboard (-c) or display scannable QR codes (--qr).
  • Track Expirations: Uses a lightweight local SQLite database to track presigned URLs and their remaining lifespan.
  • Multipart Uploads: Automatically switches to multipart uploads for files ≥ 8 MiB with smooth progress bars.
  • Self-Cleaning: Easily list expired links and prune them from R2 to keep your storage clean.

Installation

Install rink via PyPI. We recommend using uv for easy tool management, but standard pip works too.

Using uv (Recommended)

# Install as a global CLI tool on your PATH
uv tool install rink

# Or install into your active environment
uv pip install rink

Using pip or pipx

pipx install rink
# or
pip install rink

From Source (Development)

# Clone the repository and sync dependencies
git clone https://github.com/HACKE-RC/rink.git
cd rink
uv sync

# Run from the project
uv run rink --help

# Install the local checkout as a global tool
uv tool install .

One-Time Cloudflare Setup

Before using rink, you need to retrieve your Cloudflare credentials and create a bucket:

  1. Get Account ID: Go to the Cloudflare DashboardR2 → Copy the Account ID from the right sidebar.
  2. Create a Bucket: Click Create bucket in the dashboard, or run wrangler r2 bucket create <name>.
  3. Generate API Token:
    • Click Manage R2 API TokensCreate API Token.
    • Select permissions: Object Read & Write.
    • Copy the Access Key ID and Secret Access Key.
  4. (Optional for Public Links): In your bucket's page → SettingsPublic Access → Enable Public Development URL (or configure a custom domain) and copy the pub-xxxx.r2.dev address.

Quick Start

Initialize rink using the interactive setup wizard:

rink config

This wizard will prompt you for your Account ID, Access Keys, default bucket name, and preferred link configurations.

Configuration Storage

Your settings are saved at ~/.config/rink/config.toml (file mode 600 for security).

You can also use environment variables to configure rink or override config files:

  • RINK_ACCOUNT_ID
  • RINK_ACCESS_KEY_ID
  • RINK_SECRET_ACCESS_KEY
  • RINK_BUCKET
  • RINK_PUBLIC_BASE_URL

Usage & Command Reference

Uploading Files (rink up)

Upload one or more files/directories and print their shareable links.

# Upload a single file with default expiry (signed URL)
rink up report.pdf

# Upload and copy the link directly to clipboard
rink up report.pdf -c

# Generate a scannable terminal QR code for the upload
rink up report.pdf --qr

# Upload with a custom expiration (e.g. 30m, 2h, 7d, 1h30m, or bare seconds)
rink up report.pdf --expiry 1d

# Upload as a permanent public link (requires public URL setup)
rink up report.pdf --public

# Pipe content directly from stdin (requires --name)
cat logs.txt | rink up - --name system_logs.txt

# Prefix files or randomize the upload paths for privacy
rink up invoice.pdf --prefix backups/
rink up secret.docx --random

# Force browsers to download the file instead of viewing it inline
rink up photo.png --download

Upload Options

Flag Default Description
--public / --presigned --presigned Choose link type (public permanent or presigned temporary).
--expiry <duration> Config default Presigned URL duration (e.g. 30m, 2h, 7d). Max 7d.
--zip / --recursive --zip Folders: zip into one file, or upload contents recursively in parallel.
--workers <count> 4 Number of parallel upload workers for recursive directories.
--prefix <string> None Object key prefix path in the bucket.
--bucket <name> Config bucket Override the target bucket.
--name <string> Source filename Destination key name (required for stdin).
--random Off Prepend a random string to the destination key for unguessable links.
--download Off Forces the browser to download the file (Content-Disposition: attachment).
--copy, -c Off Copies the generated URL(s) to the clipboard.
--qr Off Prints a terminal QR code for the uploaded file link.
--quiet, -q Off Prints only the URL(s) (useful for scripting and piping).
--json Off Formats command output as JSON.

Listing & Managing Buckets

# List all R2 buckets in your Cloudflare account
rink buckets

# Pick a default bucket interactively
rink use

# Set default bucket directly
rink use my-bucket

Listing & Regenerating Links (rink ls, rink link, rink open)

# List all tracked uploads with their remaining lifetime
rink ls

# Filter tracked files by bucket prefix
rink ls backups/

# Filter to show only files with expired presigned links
rink ls --expired

# Regenerate a fresh URL for an existing file (without re-uploading)
rink link invoice.pdf --expiry 7d -c

# Open an uploaded file's URL in your default web browser
rink open invoice.pdf

Deleting & Revoking Access (rink rm, rink prune)

To revoke access to a file, you must delete it from the bucket.

# Delete an object and clear its tracking log
rink rm report.pdf

# Delete multiple files and skip verification prompts
rink rm image1.png image2.png -y

# Delete all R2 files whose tracked presigned links have expired
rink prune

How It Works (Under the Hood)

Since Cloudflare R2 stores raw object files rather than temporary share links, R2 has no native concept of "when a presigned link expires". A presigned URL's expiration is computed cryptographically and embedded directly in the URL query string.

To solve this, rink maintains a lightweight local SQLite database at ~/.local/share/rink/rink.db.

  • Every time you perform an upload, rink logs the object key, bucket name, and link expiration timestamp locally.
  • Running rink ls joins live bucket object information with this local log to determine exactly how much time is left on each link.
  • Objects uploaded outside of rink (or whose local log records are missing) will show up as untracked.
  • Deleting an object via rink rm deletes it from R2 and removes its tracking entry from your database.

[!NOTE] Presigned link expiration does not delete the file from R2; it only makes the URL invalid. To save bucket space, run rink prune to delete expired files from your bucket.


Development

Contributions are welcome! To set up your local development environment:

  1. Clone the repository and install dev dependencies:
    uv sync --dev
    
  2. Run tests (we use moto to mock S3/R2 requests locally; no live network calls are made):
    uv run pytest -v
    
  3. Run tests quietly:
    uv run pytest -q
    

License

This project is licensed under the MIT License.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

rink-0.2.8.tar.gz (18.1 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

rink-0.2.8-py3-none-any.whl (22.0 kB view details)

Uploaded Python 3

File details

Details for the file rink-0.2.8.tar.gz.

File metadata

  • Download URL: rink-0.2.8.tar.gz
  • Upload date:
  • Size: 18.1 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.11.19 {"installer":{"name":"uv","version":"0.11.19","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for rink-0.2.8.tar.gz
Algorithm Hash digest
SHA256 d51edc5c849aaab6b058c5e4bc1a266c8a71c57edd63ca8ba607ec77af45346a
MD5 2ede9e0f68e6f71187f23964bcf1a91d
BLAKE2b-256 521cca6e5b7d5473201040bdfa53c02ba7fccbf36950ec10c5e728d1a1f47246

See more details on using hashes here.

File details

Details for the file rink-0.2.8-py3-none-any.whl.

File metadata

  • Download URL: rink-0.2.8-py3-none-any.whl
  • Upload date:
  • Size: 22.0 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.11.19 {"installer":{"name":"uv","version":"0.11.19","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for rink-0.2.8-py3-none-any.whl
Algorithm Hash digest
SHA256 f403bc71e6edf52fe29c4ee9d26d5328447695b1204237257aea56e413f9f041
MD5 aad92ee342444f9068e434d698576dbc
BLAKE2b-256 5a00645eb8ecf994126dbb3fcc515bcabd0a3cb02b54c6e4ef8fc214e5accb41

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page