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.9.tar.gz (18.4 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.9-py3-none-any.whl (22.3 kB view details)

Uploaded Python 3

File details

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

File metadata

  • Download URL: rink-0.2.9.tar.gz
  • Upload date:
  • Size: 18.4 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.9.tar.gz
Algorithm Hash digest
SHA256 1027eb0f62934b52ab5561df171ecb470626b11c6ed69d677580fc8c02dbd74b
MD5 17e0098276e56556c23dc28835b46a95
BLAKE2b-256 c24b6d5cd8fb85304184266be7fb7f0bd2b76779834889569b7a3a2d24001661

See more details on using hashes here.

File details

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

File metadata

  • Download URL: rink-0.2.9-py3-none-any.whl
  • Upload date:
  • Size: 22.3 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.9-py3-none-any.whl
Algorithm Hash digest
SHA256 338738eb1b0f30fb6fa9630db1c43b22aaa94cb16d1683b9c885e3cb942ecc6f
MD5 448b6735238a498a49b08fee1b2fd0a3
BLAKE2b-256 011d86e770fee02c45d340d2bb2dd78ec879b80ede12fce4b74116158a22a7a0

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