mirror of
https://github.com/System-End/cdn.git
synced 2026-04-19 22:05:13 +00:00
read me
This commit is contained in:
parent
4258ae17e9
commit
77ce6315a5
2 changed files with 142 additions and 114 deletions
68
.env.example
68
.env.example
|
|
@ -1,14 +1,58 @@
|
|||
# S3 Config CF in this example
|
||||
AWS_ACCESS_KEY_ID=1234567890abcdef
|
||||
AWS_SECRET_ACCESS_KEY=abcdef1234567890
|
||||
AWS_BUCKET_NAME=my-cdn-bucket
|
||||
AWS_REGION=auto
|
||||
AWS_ENDPOINT=https://<accountid>.r2.cloudflarestorage.com
|
||||
AWS_CDN_URL=https://cdn.beans.com
|
||||
# =============================================================================
|
||||
# Cloudflare R2 Storage (S3-compatible)
|
||||
# =============================================================================
|
||||
R2_ACCESS_KEY_ID=your_access_key_id
|
||||
R2_SECRET_ACCESS_KEY=your_secret_access_key
|
||||
R2_BUCKET_NAME=your-bucket-name
|
||||
R2_ENDPOINT=https://YOUR_ACCOUNT_ID.r2.cloudflarestorage.com
|
||||
|
||||
# API
|
||||
API_TOKEN=beans # Set a secure random string
|
||||
PORT=3000
|
||||
# Public hostname for CDN URLs (used in generated links)
|
||||
CDN_HOST=cdn.hackclub.com
|
||||
|
||||
# Sentry
|
||||
SENTRY_DSN=https://your-sentry-dsn@sentry.io/project-id
|
||||
# =============================================================================
|
||||
# Hack Club OAuth
|
||||
# =============================================================================
|
||||
# Get credentials from Hack Club Auth (https://auth.hackclub.com)
|
||||
HACKCLUB_CLIENT_ID=your_client_id
|
||||
HACKCLUB_CLIENT_SECRET=your_client_secret
|
||||
# Optional: Override auth URL (defaults to staging in dev, production in prod)
|
||||
# HACKCLUB_AUTH_URL=https://auth.hackclub.com
|
||||
|
||||
# =============================================================================
|
||||
# Encryption Keys
|
||||
# =============================================================================
|
||||
# Generate with: ruby -e "require 'securerandom'; puts SecureRandom.hex(32)"
|
||||
LOCKBOX_MASTER_KEY=0000000000000000000000000000000000000000000000000000000000000000
|
||||
BLIND_INDEX_MASTER_KEY=0000000000000000000000000000000000000000000000000000000000000000
|
||||
|
||||
# Active Record Encryption (generate with: bin/rails db:encryption:init)
|
||||
ACTIVE_RECORD_ENCRYPTION_PRIMARY_KEY=your_primary_key
|
||||
ACTIVE_RECORD_ENCRYPTION_DETERMINISTIC_KEY=your_deterministic_key
|
||||
ACTIVE_RECORD_ENCRYPTION_KEY_DERIVATION_SALT=your_key_derivation_salt
|
||||
|
||||
# =============================================================================
|
||||
# Database (production only - dev uses cdn_development/cdn_test)
|
||||
# =============================================================================
|
||||
# DATABASE_HOST=localhost
|
||||
# DATABASE_USER=cdn
|
||||
# DATABASE_PASSWORD=your_password
|
||||
# DATABASE_NAME=cdn_production
|
||||
|
||||
# Solid Cache/Queue/Cable databases (optional, defaults provided)
|
||||
# CACHE_DATABASE_HOST=localhost
|
||||
# QUEUE_DATABASE_HOST=localhost
|
||||
# CABLE_DATABASE_HOST=localhost
|
||||
|
||||
# =============================================================================
|
||||
# Optional
|
||||
# =============================================================================
|
||||
# Sentry error tracking
|
||||
# SENTRY_DSN=https://your-sentry-dsn@sentry.io/project-id
|
||||
|
||||
# HashID salt (defaults to SECRET_KEY_BASE if not set)
|
||||
# HASHID_SALT=your_hashid_salt
|
||||
|
||||
# Rails configuration
|
||||
# PORT=3000
|
||||
# RAILS_MAX_THREADS=5
|
||||
# SECRET_KEY_BASE=your_secret_key_base
|
||||
|
|
|
|||
188
README.md
188
README.md
|
|
@ -14,122 +14,106 @@
|
|||
</a>
|
||||
</div>
|
||||
|
||||
---
|
||||
|
||||
## 📡 API Usage
|
||||
A Rails 8 application for hosting and managing CDN uploads, with OAuth authentication via Hack Club.
|
||||
|
||||
- All API endpoints require authentication via `Authorization: Bearer api-token` header
|
||||
- Use the API_TOKEN from your environment configuration
|
||||
- Failure to include a valid token will result in 401 Unauthorized responses
|
||||
## Prerequisites
|
||||
|
||||
### V3 API (Latest)
|
||||
<img alt="Version 3" src="https://files.catbox.moe/e3ravk.png" align="right" width="300">
|
||||
- Ruby 3.4.4 (see `.ruby-version`)
|
||||
- PostgreSQL
|
||||
- Node.js + Yarn (for Vite frontend)
|
||||
- A Cloudflare R2 bucket (or S3-compatible storage)
|
||||
|
||||
**Endpoint:** `POST https://cdn.hackclub.com/api/v3/new`
|
||||
## Setup
|
||||
|
||||
**Headers:**
|
||||
```
|
||||
Authorization: Bearer api-token
|
||||
Content-Type: application/json
|
||||
```
|
||||
1. **Clone and install dependencies:**
|
||||
```bash
|
||||
git clone https://github.com/hackclub/cdn.git
|
||||
cd cdn
|
||||
bundle install
|
||||
yarn install
|
||||
```
|
||||
|
||||
**Request Example:**
|
||||
2. **Configure environment variables:**
|
||||
```bash
|
||||
cp .env.example .env
|
||||
```
|
||||
Edit `.env` with your credentials (see below for details).
|
||||
|
||||
3. **Setup the database:**
|
||||
```bash
|
||||
bin/rails db:create db:migrate
|
||||
```
|
||||
|
||||
4. **Generate encryption keys** (for API key encryption):
|
||||
```bash
|
||||
# Generate a 32-byte hex key for Lockbox
|
||||
ruby -e "require 'securerandom'; puts SecureRandom.hex(32)"
|
||||
|
||||
# Generate a 32-byte hex key for BlindIndex
|
||||
ruby -e "require 'securerandom'; puts SecureRandom.hex(32)"
|
||||
|
||||
# Generate Active Record encryption keys
|
||||
bin/rails db:encryption:init
|
||||
```
|
||||
|
||||
5. **Start the development servers:**
|
||||
```bash
|
||||
# In one terminal, run the Vite dev server:
|
||||
bin/vite dev
|
||||
|
||||
# In another terminal, run the Rails server:
|
||||
bin/rails server
|
||||
```
|
||||
|
||||
## Environment Variables
|
||||
|
||||
See `.env.example` for the full list. Key variables:
|
||||
|
||||
| Variable | Description |
|
||||
|----------|-------------|
|
||||
| `R2_ACCESS_KEY_ID` | Cloudflare R2 access key |
|
||||
| `R2_SECRET_ACCESS_KEY` | Cloudflare R2 secret key |
|
||||
| `R2_BUCKET_NAME` | R2 bucket name |
|
||||
| `R2_ENDPOINT` | R2 endpoint URL |
|
||||
| `CDN_HOST` | Public hostname for CDN URLs |
|
||||
| `HACKCLUB_CLIENT_ID` | OAuth client ID from Hack Club Auth |
|
||||
| `HACKCLUB_CLIENT_SECRET` | OAuth client secret |
|
||||
| `LOCKBOX_MASTER_KEY` | 64-char hex key for encrypting API keys |
|
||||
| `BLIND_INDEX_MASTER_KEY` | 64-char hex key for searchable encryption |
|
||||
|
||||
## API
|
||||
|
||||
The API uses bearer token authentication. Create an API key from the web dashboard after logging in.
|
||||
|
||||
**Upload a file:**
|
||||
```bash
|
||||
curl --location 'https://cdn.hackclub.com/api/v3/new' \
|
||||
--header 'Authorization: Bearer beans' \
|
||||
--header 'Content-Type: application/json' \
|
||||
--data '[
|
||||
"https://assets.hackclub.com/flag-standalone.svg",
|
||||
"https://assets.hackclub.com/flag-orpheus-left.png"
|
||||
]'
|
||||
curl -X POST https://cdn.hackclub.com/api/v4/upload \
|
||||
-H "Authorization: Bearer YOUR_API_KEY" \
|
||||
-F "file=@image.png"
|
||||
```
|
||||
|
||||
**Response:**
|
||||
```json
|
||||
{
|
||||
"files": [
|
||||
{
|
||||
"deployedUrl": "https://hc-cdn.hel1.your-objectstorage.com/s/v3/64a9472006c4472d7ac75f2d4d9455025d9838d6_flag-standalone.svg",
|
||||
"file": "0_64a9472006c4472d7ac75f2d4d9455025d9838d6_flag-standalone.svg",
|
||||
"sha": "64a9472006c4472d7ac75f2d4d9455025d9838d6",
|
||||
"size": 4365
|
||||
},
|
||||
{
|
||||
"deployedUrl": "https://hc-cdn.hel1.your-objectstorage.com/s/v3/d926bfd9811ebfe9172187793a171a5cbcc61992_flag-orpheus-left.png",
|
||||
"file": "1_d926bfd9811ebfe9172187793a171a5cbcc61992_flag-orpheus-left.png",
|
||||
"sha": "d926bfd9811ebfe9172187793a171a5cbcc61992",
|
||||
"size": 8126
|
||||
}
|
||||
],
|
||||
"cdnBase": "https://hc-cdn.hel1.your-objectstorage.com"
|
||||
}
|
||||
**Upload from URL:**
|
||||
```bash
|
||||
curl -X POST https://cdn.hackclub.com/api/v4/upload_from_url \
|
||||
-H "Authorization: Bearer YOUR_API_KEY" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"url": "https://example.com/image.png"}'
|
||||
```
|
||||
|
||||
<details>
|
||||
<summary>V2 API</summary>
|
||||
See `/docs` in the running app for full API documentation.
|
||||
|
||||
<img alt="Version 2" src="https://files.catbox.moe/uuk1vm.png" align="right" width="300">
|
||||
## Architecture
|
||||
|
||||
**Endpoint:** `POST https://cdn.hackclub.com/api/v2/new`
|
||||
|
||||
**Headers:**
|
||||
```
|
||||
Authorization: Bearer api-token
|
||||
Content-Type: application/json
|
||||
```
|
||||
|
||||
**Request Example:**
|
||||
```json
|
||||
[
|
||||
"https://assets.hackclub.com/flag-standalone.svg",
|
||||
"https://assets.hackclub.com/flag-orpheus-left.png"
|
||||
]
|
||||
```
|
||||
|
||||
**Response:**
|
||||
```json
|
||||
{
|
||||
"flag-standalone.svg": "https://cdn.example.dev/s/v2/flag-standalone.svg",
|
||||
"flag-orpheus-left.png": "https://cdn.example.dev/s/v2/flag-orpheus-left.png"
|
||||
}
|
||||
```
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary>V1 API</summary>
|
||||
|
||||
<img alt="Version 1" src="https://files.catbox.moe/tnzdfe.png" align="right" width="300">
|
||||
|
||||
**Endpoint:** `POST https://cdn.hackclub.com/api/v1/new`
|
||||
|
||||
**Headers:**
|
||||
```
|
||||
Authorization: Bearer api-token
|
||||
Content-Type: application/json
|
||||
```
|
||||
|
||||
**Request Example:**
|
||||
```json
|
||||
[
|
||||
"https://assets.hackclub.com/flag-standalone.svg",
|
||||
"https://assets.hackclub.com/flag-orpheus-left.png"
|
||||
]
|
||||
```
|
||||
|
||||
**Response:**
|
||||
```json
|
||||
[
|
||||
"https://cdn.example.dev/s/v1/0_flag-standalone.svg",
|
||||
"https://cdn.example.dev/s/v1/1_flag-orpheus-left.png"
|
||||
]
|
||||
```
|
||||
</details>
|
||||
|
||||
# Technical Details
|
||||
|
||||
- **Storage Structure:** `/s/v3/{HASH}_{filename}`
|
||||
- **File Naming:** `/s/{slackUserId}/{unix}_{sanitizedFilename}`
|
||||
- **Rails 8** with **Vite** for frontend assets
|
||||
- **Phlex** + **Primer ViewComponents** for UI
|
||||
- **Active Storage** with Cloudflare R2 backend
|
||||
- **Solid Queue/Cache/Cable** for background jobs and caching (production)
|
||||
- **Pundit** for authorization
|
||||
- **Lockbox + BlindIndex** for API key encryption
|
||||
|
||||
<div align="center">
|
||||
<br>
|
||||
<p>Made with 💜 for Hack Club</p>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue