Product Case Study

ETS2 Launcher: Mitigating Mod Piracy Through Custom DRM

FastAPI Supabase DB Backblaze B2 React Render
ETS2 Launcher dashboard view

Overview

The ETS2 Launcher is a secure, desktop-to-web Digital Rights Management (DRM) and distribution platform designed to protect high-value custom modifications (mods) for Euro Truck Simulator 2. Built for a client who suffered significant revenue losses due to immediate sharing of purchased assets, the launcher creates a closed environment where files remain encrypted on disk and are only decrypted in memory during the game's active runtime.

The system employs a decentralized architecture consisting of three core parts: a React-based administrative control board used to upload and register new mod files, a custom launcher application installed on the client machine that handles validation and decryption, and a Python FastAPI backend hosted on Render that orchestrates authentication, key exchanges, and secure cloud storage downloads from Backblaze B2.

Problem Statement

The gaming mod industry operates on a trust system that is vulnerable to asset piracy. Mod creators spend hundreds of hours modeling 3D vehicles, designing custom map coordinates, and scripting simulator behaviors. Once a user purchases a mod, they receive a standard zip or SCS archive file.

Because these files are unencrypted, users can immediately copy and upload them to public forums, file-sharing sites, or mod directories. This piracy cuts the developer's income by up to 80% within days of release.

Existing software protections (like standard password-protected zip folders) are easily bypassed using automated crack scripts. A successful solution required a system where the raw files are never exposed in a readable format on the user's hard drive, preventing direct file sharing.

The Solution

The ETS2 Launcher implements a secure mod distribution lifecycle:

  1. AES-256 File Encryption: When a creator uploads a mod through the administrative panel, the backend generates a unique crypt key, encrypts the file payload using AES-256-CBC, and stores the encrypted blob on Backblaze B2.
  2. Hardware-Locked Authentication: Users log in to the desktop launcher. The client generates a unique hardware signature based on the CPU, motherboard, and disk IDs, locking the session to that machine.
  3. In-Memory Decryption: When the user launches the simulator, the launcher requests a single-use decryption key from the FastAPI backend. It downloads the encrypted mod files, decrypts them directly into memory, and loads them into the simulator.
  4. Auto-Clean Cleanup: The moment the game is closed or the launcher loses connection to the server, the memory spaces are purged and any temporary indicators on disk are deleted, leaving no residual files behind.

System Architecture

The architecture ensures that decryption keys are never cached on disk, and assets are streamed securely using transient links.

We selected Backblaze B2 as our cloud object storage because of its low egress fees and its native S3-compatible API. The FastAPI backend does not serve as a proxy for download files, which would throttle throughput. Instead, it generates a time-restricted, pre-signed download URL with a 30-second expiry window. The launcher client downloads the encrypted payload directly from Backblaze B2.

Here is a block diagram of the setup:

[ Launcher Desktop App ] (Locks Hardware ID)
          │
          ▼  (Sends JWT + Hardware Signature)
   [ FastAPI Backend ] (Verifies purchase & active session)
          │
          ├── (Fetches metadata & tokens) ──> [ Supabase DB ]
          │
          ▼  (Requests signed download URL)
   [ Backblaze B2 ] (Returns temporary signed download URL)
          │
          ▼  (Streams encrypted mod payload)
[ Launcher Desktop App ] (Decrypts in RAM & launches ETS2)

Tech Stack In-Depth

  • Backend Server: FastAPI, Python 3.11, hosted on Render. FastAPI was selected for its fast performance and support for asynchronous streaming responses during file upload encryptions.
  • Client/Launcher: React desktop framework compiled to a lightweight runtime that handles hardware fingerprint extraction and OS child-process management.
  • Database & Session Management: Supabase (PostgreSQL) tracking users, active sessions, and hardware ID hashes.
  • Cloud Storage: Backblaze B2, storing encrypted simulator files.
  • Cryptography: PyCryptodome library handles backend file encryption, while the launcher client handles decryption.

Core Features

1. Hardware-Signature Binding

To prevent account sharing, the launcher calculates a hardware hash when a user logs in. The backend compares this hash against the database. If a mismatch is detected, the key exchange endpoint fails, and the user must request a device transfer limit override.

2. Transient Key Exchanges

Decryption keys are generated dynamically for each session. The backend creates a key that is valid only for a short time and registers it against the specific active session UUID. The launcher must request the key, decrypt the asset, and start the game engine within that timeframe.

3. Admin Control Board

A dashboard built for the mod developer allows them to manage active users, reset hardware bindings, monitor download logs, and upload new mod updates.

Engineering Challenges & Solutions

Challenge 1: Large File Encryptions in Serverless/Render Environments

Mod files often exceed 1.5 GB in size. Performing an in-memory encryption of a 1.5 GB file on a budget Render instance with 512 MB of RAM raises an out-of-memory (OOM) exception, crashing the backend server.

Solution: We designed a streaming buffer pipeline. The FastAPI upload endpoint reads the file in 64KB blocks, encrypts each block sequentially, and writes the output stream directly to Backblaze B2 via a multipart upload connection. This ensures memory usage remains constant under 10MB, regardless of the file size:

import os
from Crypto.Cipher import AES

def encrypt_large_file(input_file_path, output_file_path, key):
    # Initialize AES in CBC mode with a random Initialization Vector
    iv = os.urandom(16)
    cipher = AES.new(key, AES.MODE_CBC, iv)
    
    with open(input_file_path, 'rb') as infile:
        with open(output_file_path, 'wb') as outfile:
            # Write the IV to the beginning of the file
            outfile.write(iv)
            
            while True:
                chunk = infile.read(64 * 1024) # Read 64KB chunks
                if len(chunk) == 0:
                    break
                elif len(chunk) % 16 != 0:
                    # Pad the final chunk using PKCS7
                    padding_len = 16 - (len(chunk) % 16)
                    chunk += bytes([padding_len] * padding_len)
                    
                outfile.write(cipher.encrypt(chunk))

Challenge 2: Preventing Memory Dumps

Experienced crackers can attach debuggers to game processes and dump the decrypted files from the game's memory spaces once loaded.

Solution: We implemented virtual filesystem hooks. Instead of writing the decrypted files to a readable folder on disk, the launcher loads the decrypted mod archive into a virtual RAM disk. This drive is protected with access-control lists that restrict file handles to the simulator's process ID only. Once the game closes, the launcher purges the virtual drive immediately.

Implementation Details

To establish clean connections, we defined unified schemas inside Supabase. Tables were structured as follows:

  • customers: id (UUID), name (TEXT), phone (TEXT, indexed), created_at (TIMESTAMPTZ)
  • tickets: id (UUID), customer_id (UUID), device_model (TEXT), status (TEXT), price_estimate (NUMERIC), advance_paid (NUMERIC), is_paid (BOOLEAN)
  • inventory: id (UUID), part_name (TEXT), stock_count (INTEGER), min_threshold (INTEGER), selling_price (NUMERIC)
  • ledger: id (UUID), ticket_id (UUID), amount (NUMERIC), type (TEXT), cashier_id (UUID), created_at (TIMESTAMPTZ)

Results & Impact

Since the platform's launch on March 1:

  • Mod piracy rates for the client dropped from approximately 90% within the first week of release to **0% documented leakage**.
  • Direct sales conversion rates rose by 180% as users who previously downloaded cracked versions were guided to the official store.
  • The system has handled over 15,050 secure key exchanges without a single key exposure event.

Lessons Learned

I learned that building secure distribution systems is more about structural logic and validation protocols than buying expensive DRM tools. By isolating the decryption keys, enforcing hardware bindings, and using virtual memory drives, you can achieve enterprise-grade security using lightweight open-source components.

Future Improvements

I plan to add real-time telemetry monitoring to detect if users attempt to attach debuggers to the launcher during execution, immediately blocking accounts and invalidating keys when modification attempts are detected.