Skip to content

feat(ltk-manager): one-click mod install via custom URI protocol (ltk://) #124

@Crauzer

Description

@Crauzer

Summary

Register a custom URI protocol (ltk://) so mod distribution websites can offer an "Install in LTK Manager" button that opens the app and triggers a mod install — similar to how steam://, vscode://, and spotify:// links work.

End-to-End Flow

 Website                    Browser                  OS                    LTK Manager
┌──────────┐  click    ┌───────────┐  protocol  ┌─────────┐  launch   ┌─────────────┐
│ Install   │────────> │ "Open LTK │──────────> │ Registry│────────> │ Parse URL   │
│ Button    │          │  Manager?" │            │ Lookup  │          │ Show confirm│
│           │          │  [Allow]   │            │         │          │ Download mod│
└──────────┘          └───────────┘            └─────────┘          └─────────────┘
  1. User clicks "Install in LTK Manager" on a mod distribution site
  2. Browser recognizes ltk:// protocol and asks to open the app (or auto-opens if previously allowed)
  3. OS looks up the registered protocol handler and launches LTK Manager (or focuses it if already running)
  4. App parses the URL, shows a confirmation dialog with mod details, downloads and installs on confirm

Protocol Schema

ltk://install?url=<download_url>&name=<mod_name>&checksum=<sha256>&source=<site_name>

Examples

# Direct file download
ltk://install?url=https://modskin.com/files/dark-star-aatrox.modpkg&checksum=sha256:abc123...

# API-based (site implements the standard mod endpoint)
ltk://install?api=https://api.modskin.com/v1/mods/dark-star-aatrox

# Minimal (just a URL, app infers the rest from file metadata)
ltk://install?url=https://modskin.com/files/dark-star-aatrox.modpkg

Parameters

Param Required Description
url yes* Direct download URL for the .modpkg or .fantome file
api yes* API endpoint URL returning mod metadata (alternative to url)
checksum no sha256:<hex> for integrity verification
name no Display name for the confirmation dialog
source no Name of the originating site (shown in UI for trust context)

* One of url or api is required.

Mod Distribution API Standard

For richer integration via the api= parameter, sites can implement a simple REST endpoint:

GET /api/v1/mods/{slug-or-id}
{
  "name": "dark-star-aatrox",
  "displayName": "Dark Star Aatrox",
  "version": "2.1.0",
  "authors": [{ "name": "SkinCreator42" }],
  "description": "Custom Dark Star themed Aatrox skin",
  "thumbnailUrl": "https://modskin.com/thumbs/dark-star-aatrox.webp",
  "downloadUrl": "https://cdn.modskin.com/files/dark-star-aatrox-2.1.0.modpkg",
  "checksum": "sha256:9f86d081884c7d659a2feaa0c55ad015...",
  "fileSize": 4521984,
  "format": "modpkg",
  "createdAt": "2026-01-15T10:30:00Z",
  "updatedAt": "2026-02-10T14:22:00Z"
}

This allows the app to show a rich confirmation dialog with thumbnail, description, author, and verified metadata before downloading anything.

Website Integration

Simple HTML (any site)

<a href="ltk://install?url=https://example.com/mods/cool-skin.modpkg&name=Cool%20Skin">
  Install in LTK Manager
</a>

With fallback (app not installed)

<a href="ltk://install?url=..." id="install-btn">Install in LTK Manager</a>

<script>
  document.getElementById('install-btn').addEventListener('click', (e) => {
    setTimeout(() => {
      window.location.href = 'https://leaguetoolkit.dev/download';
    }, 2000);
  });
</script>

Optional JS SDK (for partner sites)

<script src="https://leaguetoolkit.dev/sdk.js"></script>

<button onclick="LTK.install({
  url: 'https://example.com/mods/cool-skin.modpkg',
  name: 'Cool Skin',
  checksum: 'sha256:abc...'
})">
  Install in LTK Manager
</button>

The SDK handles protocol detection, fallback to download page, and branded button styling.

Security Requirements

Protocol handlers are an attack surface and must be treated carefully:

  1. Always show a confirmation dialog — never silently install. Show mod name, source site, file size, and require explicit user approval
  2. HTTPS only — reject http:// download URLs entirely
  3. Checksum verification — if provided, verify before installing; if not, show an "unverified source" warning
  4. Temp download — download to a temp directory, validate it's a real .modpkg/.fantome file, then move to library
  5. Rate limiting — ignore rapid-fire protocol invocations (prevents abuse from malicious pages)
  6. URL sanitization — strict URL parsing, reject malformed input, no path traversal
  7. Domain allowlist (optional) — settings option for users to restrict installs to trusted domains only

Implementation Notes

Tauri Deep Link Plugin

Tauri provides tauri-plugin-deep-link which handles OS-level protocol registration:

  • Windows: Writes HKEY_CLASSES_ROOT\ltk registry key at install/setup time
  • macOS: Adds URL scheme to Info.plist
  • Linux: Adds x-scheme-handler/ltk to .desktop file

App-Side Flow

1. Receive deep link URL (on launch or while running)
2. Parse and validate URL parameters
3. If `api=` param: fetch mod metadata from the API endpoint
   If `url=` param: use provided metadata or show minimal info
4. Show confirmation dialog:
   - Mod name, version, author, thumbnail (if available)
   - Source site name
   - File size
   - "Verified" badge if checksum provided, "Unverified" warning if not
   - [Cancel] [Install] buttons
5. On confirm: download to temp dir → verify checksum → validate format → install to library
6. Show success toast with "View in Library" link

Single Instance

The app should enforce single-instance behavior so that protocol links focus the existing window rather than launching duplicates. Tauri's tauri-plugin-single-instance handles this.

Future Considerations

  • Bulk install: ltk://install-collection?api=https://... for curated mod packs
  • Update protocol: ltk://update?mod=dark-star-aatrox&url=... to update an already-installed mod
  • Local HTTP server fallback: Some sandboxed browsers may not support custom protocols; a local server on a fixed port (localhost:21420) could serve as a secondary mechanism

Metadata

Metadata

Assignees

Labels

Projects

Status

Todo

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions