Skip to content

0xSockLove/metadata

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1 Commit
 
 

Repository files navigation

SockLove Metadata Standard

"The metadata standard. Every Relic conforms."


Architecture

Every Relic has two layers.

Public (SFW) — anyone can fetch. Stored permanently on IPFS. Private (NSFW) — Witnesses only. Served via the DRM server. The key never leaves the server.


Token Metadata

Stored on IPFS. URI written immutably into the Ethereum event log at mint time.

{
  "name": "SockLove #{TOKEN_ID} — {TITLE}",
  "description": "{DESCRIPTION}",
  "image": "ipfs://{SAFE_POSTER_CID}",
  "animation_url": "ipfs://{SAFE_TEASER_CID}",
  "attributes": [
    { "trait_type": "Type",         "value": "{TYPE}" },
    { "trait_type": "Creators",     "value": "Sockpusher & Sockthief" },
    { "trait_type": "Moments",      "value": {MOMENTS} },
    { "trait_type": "Duration",     "value": "{DURATION}" },
    { "trait_type": "Release Date", "value": "{YYYY-MM-DD}" },
    { "trait_type": "Edition Size", "value": {EDITION_SIZE} },
    { "trait_type": "Rating",       "value": "NSFW (18+)" }
  ]
}

Fields

Field Value
name "SockLove #1 — The First Night". Em dash. Space on both sides.
description Narrative. Plain text. No Markdown. No URLs.
image ipfs:// URI of the SFW poster JPEG.
animation_url ipfs:// URI of the SFW teaser MP4.

Attributes

Trait Type Notes
Type string "Photo" or "Video"
Creators string Always "Sockpusher & Sockthief"
Moments integer Number of photos. Always 1 for video tokens.
Duration string "00:00:00" for photo tokens. "hh:mm:ss" for video tokens.
Release Date string "YYYY-MM-DD"
Edition Size integer Number of copies minted.
Rating string Always "NSFW (18+)"

Content

Private content is not referenced in public metadata.

The PWA discovers the DRM server via the ENS text record drm on socklove.eth. Authentication is via SIWE. Access is verified on-chain per request via balanceOf. Content is decrypted server-side and streamed as plain bytes. The decryption key never reaches the client.


Content Preparation

Master export

  • Photo: Full-resolution JPEG, maximum quality, sRGB
  • Video: DNxHR HQX, full resolution

Safe assets

  • Safe poster: 2000px long edge, JPEG 85%, sRGB
  • Safe teaser: H.264, 1920×1080, CRF 23, AAC 128k, +faststart

EXIF

Strip all metadata from every file before any upload or encryption.

exiftool -all= *.jpg *.mov *.mp4

Watermark

Apply a visible SockLove logo watermark to all content files and safe assets before encryption. What gets encrypted is already watermarked — no clean copy ever exists.

Photos — ImageMagick:

magick input.jpg \
  \( watermark.png -resize 15% -alpha set -evaluate multiply 0.5 \) \
  -gravity SouthEast -geometry +40+40 \
  -composite output_watermarked.jpg

Videos — FFmpeg:

ffmpeg -i input.mp4 -i watermark.png \
  -filter_complex "[1:v]scale=iw*0.1:-1,format=rgba,colorchannelmixer=aa=0.5[wm];[0:v][wm]overlay=W-w-40:H-h-40" \
  -c:v libx264 -crf 23 -c:a copy \
  output_watermarked.mp4

Encryption — Photos

AES-256-GCM. Performed by the DRM server (Node.js crypto module).

# Generate 32-byte key
openssl rand 32 > gallery.key
import fs from 'fs';
import { createCipheriv, randomBytes } from 'crypto';

const key = fs.readFileSync('gallery.key');
const iv = randomBytes(12);                          // 96-bit nonce for GCM
const cipher = createCipheriv('aes-256-gcm', key, iv);

const encrypted = Buffer.concat([cipher.update(plaintext), cipher.final()]);
const tag = cipher.getAuthTag();

// Persist: iv + tag + encrypted

Store the gallery key and all encrypted files on the DRM server. Pin safe assets to IPFS — record CIDs.

Encryption — Video

AES-128-CBC. Performed by FFmpeg via -hls_key_info_file. For segment-level encryption, HLS uses AES-128-CBC as the standard method.

# 1. Generate 16-byte AES-128 key
openssl rand 16 > hls.key

# 2. Create keyinfo file (key URI, key path, optional IV)
echo "https://placeholder/hls.key" >  hls.keyinfo
echo "hls.key"                     >> hls.keyinfo
echo "$(openssl rand -hex 16)"     >> hls.keyinfo

# 3. Transcode to encrypted HLS
ffmpeg -i input_watermarked.mp4 \
  -c:v libx264 -crf 23 -c:a aac -b:a 128k \
  -hls_time 6 \
  -hls_key_info_file hls.keyinfo \
  -hls_playlist_type vod \
  -hls_segment_filename "segments/%03d.ts" \
  playlist.m3u8

The DRM server rewrites the playlist before serving — removing the key reference and rewriting all segment paths to authenticated proxy endpoints. The video player receives no key. The key never leaves the server. Quality is selected automatically for the Witness's connection.

Store encrypted segments, playlist, and key on the DRM server. Pin safe assets to IPFS — record CIDs.


Minting Workflow

1  Shoot and edit
2  Produce safe poster and safe teaser
3  Strip EXIF from all files
4  Apply visible watermark to all content files and safe assets
5  Encrypt content — store on DRM server
6  Pin safe poster and safe teaser to IPFS — record CIDs
7  Build token metadata JSON — verify no {PLACEHOLDER} strings remain
8  Pin token metadata to IPFS — record CID
9  Mint via the Safe (socklove.eth):
   mint("ipfs://{METADATA_CID}", {EDITION_SIZE})
   └── Sockpusher signs
   └── Sockthief signs
   └── Relic is live

Both founders must sign step 9. A Relic without both signatures does not exist.


socklove.eth · Ethereum · 🧦💜🔥

About

Canonical metadata specification for SockLove Relics.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Packages

 
 
 

Contributors